Calling Uno from ObjC async callback


#1

Hi,

I’m trying to call back to Uno from an async ObjC block callback. I’ve tried as many variants and possibilities as I can think of but can’t get it to work. Any pointers would be very welcome.

In the code snippet, the functions ‘GetAppBadgeCount’ and ‘ResetAppBadgeCount’ work fine. It is the ‘GetDeliveredNotices’ that is giving me grief. What I am trying to do is get an NSArray back into JavaScript in MainView.ux (I’m passing back a string right now just to get the framework working). The approach I am trying is to raise an event in AppBadge.uno and react to that event in MainView.ux. The problem that I have is getting from the async ObjC callback to Uno…

using Fuse;
using Fuse.Scripting;
using Fuse.iOS;
using Uno.UX;
using Uno.Compiler.ExportTargetInterop;

[ForeignInclude(Language.ObjC, "UserNotifications/UserNotifications.h")]

[UXGlobalModule]
public class AppBadge : NativeEventEmitterModule {
  static readonly AppBadge _instance;

  public AppBadge() : base(false, "onNoticesRetrieved") {
if (_instance != null) return;

_instance = this;
Resource.SetGlobalKey(_instance, "AppBadge");
AddMember(new NativeFunction("GetAppBadgeCount", (NativeCallback)GetWrapper));
AddMember(new NativeFunction("ResetAppBadgeCount", (NativeCallback)ResetWrapper));
AddMember(new NativeFunction("GetDeliveredNotices", (NativeCallback)GetNoticesWrapper));
  }

  void RetrievedNotices(string str) {
if (str == null)
  Emit("onNoticesRetrieved", "No fish today");
else
  Emit("onNoticesRetrieved", str);
  }

  public object GetWrapper(Context c, object[] args) {
if defined(iOS || Android) {
  return GetAppBadgeCount();
}
else return 0;
  }

  public object ResetWrapper(Context c, object[] args) {
if defined(iOS || Android) {
  return ResetAppBadgeCount();
}
else return 0;
  }

  public object GetNoticesWrapper(Context c, object[] args) {
if defined(iOS || Android) {
  return GetDeliveredNotices();
}
  }

  [Foreign(Language.ObjC)]
  public extern(iOS) int GetAppBadgeCount() @{
return [[UIApplication sharedApplication] applicationIconBadgeNumber];
  @}

  public extern(iOS) int ResetAppBadgeCount() @{
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
return 0;
  @}

  public extern(iOS) int GetDeliveredNotices() @{
id<UnoObject> that = _this;
[[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^void (NSArray *notifications) {
  @{AppBadge:Of(that).RetrievedNotices(string):Call(@"Fresh fish today")};
}];
return 0;
  @}

// Application icon badges for Android have not been implemented yet so we provide these "null" functions
// to keep the compiler happy
  [Foreign(Language.Java)]
  public extern(Android) int GetAppBadgeCount() @{
return 0;
  @}

  public extern(Android) int ResetAppBadgeCount() @{
return 0;
  @}
}

Regards,
AC


#2

Problem fixed after much trial-and-error…


#3

Please post your fixed foreign code. It would benefit others.


#4

The problem was this directive:
[Foreign(Language.ObjC)]

If you look at the attached code sample, there is only one foreign code directive. I could not find anything in the documentation that told me whether a directive remains active until another directive or whether it remains active only for the immediately following function definition.
When I had only GetAppBadgeCount and ResetAppBadgeCount everything worked fine which led me to believe that the foreign code directive remained active up to the point where another directive is encountered.
This was not true. When I addd the third function definition - GetDeliveredNotices - it all fell apart. The fix was to put a foreign code directive in front of every function definition.

Regards,
ac