iOS Question Local notification in Foreground

Semen Matusovskiy

Well-Known Member
Licensed User
Hi --

I want to show local notification similar like it looks in background.

As I read, it's possible since IOS 10 (to do something inside UNUserNotificationCenterDelegate).
Does anybody has a sample (or maybe this already discussed on forum and I did not find) ?

I don't need actions etc. Simply system view. There is a description
https://developer.apple.com/documen.../1649518-usernotificationcenter?language=objc and even a code, which looks very close to my needs ( https://www.b4x.com/android/forum/threads/notifications-with-actions.100623/#content ), but my knowledge about objective-c is zero.
 
Last edited:

Brandsum

Well-Known Member
Licensed User
I thought that it is not possible. But thank you for the apple documentation. I was looking for it for so long. I will try it today and will post if i succeed.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Full example:
B4X:
Sub Process_Globals
   Public App As Application
   Public NavControl As NavigationController
   Private Page1 As Page
End Sub

Private Sub Application_Start (Nav As NavigationController)
   NavControl = Nav
   Page1.Initialize("Page1")
   Page1.Title = "Page 1"
   Page1.RootPanel.Color = Colors.White
   NavControl.ShowPage(Page1)
   App.RegisterUserNotifications(True, True, True)
   Dim NotificationCenter As NativeObject
   NotificationCenter = NotificationCenter.Initialize("UNUserNotificationCenter").RunMethod("currentNotificationCenter", Null)
   NotificationCenter.SetField("delegate", Me)
End Sub

Sub Page1_Click
   CreateNotificationWithContent("This is the title", "Body", "identifer 2", "category 1", 1000)
End Sub

Sub CreateNotificationWithContent(Title As String, Body As String, Identifier As String, Category As String, MillisecondsFromNow As Long)
   Dim ln As NativeObject
   ln = ln.Initialize("UNMutableNotificationContent").RunMethod("new", Null)
   ln.SetField("title", Title)
   ln.SetField("body", Body)
   Dim n As NativeObject
   ln.SetField("sound", n.Initialize("UNNotificationSound").RunMethod("defaultSound", Null))
   If Category <> "" Then ln.SetField("categoryIdentifier", Category)
   Dim trigger As NativeObject
   trigger = trigger.Initialize("UNTimeIntervalNotificationTrigger").RunMethod("triggerWithTimeInterval:repeats:", Array(MillisecondsFromNow / 1000, False))
   Dim request As NativeObject
   request = request.Initialize("UNNotificationRequest").RunMethod("requestWithIdentifier:content:trigger:", _
       Array(Identifier, ln, trigger))
   Dim NotificationCenter As NativeObject
   NotificationCenter = NotificationCenter.Initialize("UNUserNotificationCenter").RunMethod("currentNotificationCenter", Null)
   NotificationCenter.RunMethod("addNotificationRequest:", Array(request))
End Sub


Private Sub Page1_Resize(Width As Int, Height As Int)
   
End Sub

Private Sub Application_Background
   
End Sub

#AdditionalLib: UserNotifications.framework
#if OBJC
#import <UserNotifications/UserNotifications.h>
@end
@interface b4i_main (notification) <UNUserNotificationCenterDelegate>
@end
@implementation b4i_main (notification)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
        completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound );
   }
#End If
 
Upvote 0

Brandsum

Well-Known Member
Licensed User
Full example:
B4X:
Sub Process_Globals
   Public App As Application
   Public NavControl As NavigationController
   Private Page1 As Page
End Sub

Private Sub Application_Start (Nav As NavigationController)
   NavControl = Nav
   Page1.Initialize("Page1")
   Page1.Title = "Page 1"
   Page1.RootPanel.Color = Colors.White
   NavControl.ShowPage(Page1)
   App.RegisterUserNotifications(True, True, True)
   Dim NotificationCenter As NativeObject
   NotificationCenter = NotificationCenter.Initialize("UNUserNotificationCenter").RunMethod("currentNotificationCenter", Null)
   NotificationCenter.SetField("delegate", Me)
End Sub

Sub Page1_Click
   CreateNotificationWithContent("This is the title", "Body", "identifer 2", "category 1", 1000)
End Sub

Sub CreateNotificationWithContent(Title As String, Body As String, Identifier As String, Category As String, MillisecondsFromNow As Long)
   Dim ln As NativeObject
   ln = ln.Initialize("UNMutableNotificationContent").RunMethod("new", Null)
   ln.SetField("title", Title)
   ln.SetField("body", Body)
   Dim n As NativeObject
   ln.SetField("sound", n.Initialize("UNNotificationSound").RunMethod("defaultSound", Null))
   If Category <> "" Then ln.SetField("categoryIdentifier", Category)
   Dim trigger As NativeObject
   trigger = trigger.Initialize("UNTimeIntervalNotificationTrigger").RunMethod("triggerWithTimeInterval:repeats:", Array(MillisecondsFromNow / 1000, False))
   Dim request As NativeObject
   request = request.Initialize("UNNotificationRequest").RunMethod("requestWithIdentifier:content:trigger:", _
       Array(Identifier, ln, trigger))
   Dim NotificationCenter As NativeObject
   NotificationCenter = NotificationCenter.Initialize("UNUserNotificationCenter").RunMethod("currentNotificationCenter", Null)
   NotificationCenter.RunMethod("addNotificationRequest:", Array(request))
End Sub


Private Sub Page1_Resize(Width As Int, Height As Int)
  
End Sub

Private Sub Application_Background
  
End Sub

#AdditionalLib: UserNotifications.framework
#if OBJC
#import <UserNotifications/UserNotifications.h>
@end
@interface b4i_main (notification) <UNUserNotificationCenterDelegate>
@end
@implementation b4i_main (notification)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
        completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound );
   }
#End If
Thank you so much! Is there any way to add an image to local notifications?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
One question only. I can't check, how it works (exactly does not work) in IOS 10-.
My guess is that the app will crash on startup. You need to test it.

You can also set the the #MinVersion to 10. iOS 9- can be ignored: https://developer.apple.com/support/app-store/

Is there any way to add an image to local notifications?
Should be possible with some NativeObject work. You need to add attachments: https://developer.apple.com/documen...649987-attachmentwithidentifier?language=objc
 
Upvote 0

Brandsum

Well-Known Member
Licensed User
B4X:
Public Sub CreateNotificationWithContent(Title As String, subTitle As String, Body As String, ImageURL As String, Identifier As String, Category As String, MillisecondsFromNow As Long)
    Dim ln As NativeObject
    ln = ln.Initialize("UNMutableNotificationContent").RunMethod("new", Null)
    ln.SetField("title", Title)
    If subTitle <> "" Then ln.SetField("subtitle", subTitle)


    If ImageURL <> "" Then
        Dim imageNSURL As NativeObject
        imageNSURL = imageNSURL.Initialize("NSURL").RunMethod("fileURLWithPath:",Array(ImageURL))
        Dim attachment As NativeObject = Me
        ln.SetField("attachments", attachment.RunMethod("createAttachment:",Array(imageNSURL)))
    End If


    ln.SetField("body", Body)
    Dim n As NativeObject
    ln.SetField("sound", n.Initialize("UNNotificationSound").RunMethod("defaultSound", Null))
    If Category <> "" Then ln.SetField("categoryIdentifier", Category)
    Dim trigger As NativeObject
    trigger = trigger.Initialize("UNTimeIntervalNotificationTrigger").RunMethod("triggerWithTimeInterval:repeats:", Array(MillisecondsFromNow / 1000, False))
    Dim request As NativeObject
    request = request.Initialize("UNNotificationRequest").RunMethod("requestWithIdentifier:content:trigger:", _
       Array(Identifier, ln, trigger))
    Dim NotificationCenter As NativeObject
    NotificationCenter = NotificationCenter.Initialize("UNUserNotificationCenter").RunMethod("currentNotificationCenter", Null)
    NotificationCenter.RunMethod("addNotificationRequest:", Array(request))
End Sub

#if OBJC
-(NSArray *) createAttachment: (NSURL *)imgurl{
    NSError *error = nil;
    UNNotificationAttachment *attachment;
    attachment = [UNNotificationAttachment attachmentWithIdentifier:@"imageID"
                                                          URL:imgurl
                                                      options:nil
                                                        error:&error];
    NSArray *arr = @[attachment];
    return arr;
}

#End If

Usage:
B4X:
CreateNotificationWithContent("title","sub title","body text",File.Combine(File.DirLibrary,"imgname.jpg"),"id1","cat1",1000)
 
Upvote 0

Semen Matusovskiy

Well-Known Member
Licensed User
Brandsum --

Did you check with File.DirAssets ? Probably, I did something wrong, but first time after app started, the result was successful. But then I get an error that: an icon in Assets is not found.
 
Upvote 0

Brandsum

Well-Known Member
Licensed User
Did you check with File.DirAssets ?
No. Actually, I was using for push notification. So I'm storing the image in Dir.DirLibrary and then pulling from that folder to show inside the notification.

You can copy the image asset from DirAsset to DirLibrary and then use the new path.
 
Upvote 0

Semen Matusovskiy

Well-Known Member
Licensed User
I also use for pushes. But a problem in local notifications as it is.

I copied an icon to Dir.DirLibrary. Then I tried to call CreateNotificationWithContent some times. I mean
CreateNotificationWithContent ...
Sleep (2000)
CreateNotificationWithContent ...

First time all is Ok. But result of second we get [__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]

After some experiments, I understood - CreateNotificationWithContent subroutine kills my icon.
B4X:
File.Copy (File.DirAssets,"TransparentLogo.png", File.DirLibrary, "TransparentLogo.png")
CreateNotificationWithContent ("title","sub title","body text",File.Combine(File.DirLibrary,"TransparentLogo.png"),"id1","cat1", 10)
   Sleep (1000)

    Log (File.Exists (File.DirLibrary,"TransparentLogo.png"))   '  Not found !!!

    File.Copy (File.DirAssets,"TransparentLogo.png", File.DirLibrary, "TransparentLogo.png")
   CreateNotificationWithContent ("title","sub title","body text",File.Combine(File.DirLibrary,"TransparentLogo.png"),"id2","cat1", 10)
   Sleep (2000)

    Log (File.Exists (File.DirLibrary,"TransparentLogo.png")) ' Not found !!!

A workaround is simple (to copy each time before CreateNotificationWithContent), but I don't understand IOS (?) jokes.
 
Last edited:
Upvote 0

Brandsum

Well-Known Member
Licensed User
After some experiments, I understood - CreateNotificationWithContent subroutine kills my icon.
Yes. That happened to me too.

UNNotificationAttachment:
The system validates the content of attached files before scheduling the corresponding notification request. If an attached file is corrupted, invalid, or of an unsupported file type, the notification request is not scheduled for delivery. Once validated, attached files are moved into the attachment data store so that they can be accessed by the appropriate processes. Attachments located inside an app’s bundle are copied instead of moved.
 
Last edited:
Upvote 0

Brandsum

Well-Known Member
Licensed User
But why are you using sleep? just change the time of second notification in the last parameter. Set first one to 10 (as per your code) and second one to 2000. So first one will show immediately and second one will show after 2sec.
 
Upvote 0

Semen Matusovskiy

Well-Known Member
Licensed User
Sleep allows IOS to continue and to process local notification. If simply execute CreateNotificationWithContent twice, nothing happens (exactly, will happend later)

BTW,
Attachments located inside an app’s bundle are copied instead of moved

As I understand, DirAssets should work, but doesn't (IOS 12.4). At least, in my code.
 
Last edited:
Upvote 0

Brandsum

Well-Known Member
Licensed User
Sleep allows IOS to continue and to process local notification. If simply execute CreateNotificationWithContent twice, nothing happens (exactly, will happend later)
But without using the sleep function notification scheduling is working fine for me. The first one is coming immediately and the second one is coming after 2sec.

As I understand, DirAssets should work, but doesn't (IOS 12.4). At least, in my code.
If you run your app in release mode then it will not delete the app bundle asset.
 
Upvote 0
Top