Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Ports/iOSPort/nativeSources/CodenameOne_GLAppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
#ifdef CN1_INCLUDE_NOTIFICATIONS
#import <UserNotifications/UserNotifications.h>
#endif
// Legacy compatibility flag (off by default). When defined, the AppDelegate calls
// requestAuthorizationWithOptions in didFinishLaunchingWithOptions, restoring the
// pre-issue-#4876 behavior where the system notification prompt fires at launch.
// Enable from the build hint ios.notificationPermissionAtLaunch=true.
//#define CN1_NOTIFICATION_PERMISSION_AT_LAUNCH

@class CodenameOne_GLViewController;

Expand Down
9 changes: 8 additions & 1 deletion Ports/iOSPort/nativeSources/CodenameOne_GLAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -355,14 +355,21 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
#ifdef CN1_INCLUDE_NOTIFICATIONS
if (@available(iOS 10, *)) {
if (isIOS10()) {
// Set the notification center delegate at launch so delivery callbacks route
// correctly. The auth prompt is deferred to registerPush / sendLocalNotification
// so the developer can show their own rationale first (matches Android, see
// issue #4876). Set the ios.notificationPermissionAtLaunch=true build hint to
// restore the legacy launch-time prompt for backward compatibility.
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
#ifdef CN1_NOTIFICATION_PERMISSION_AT_LAUNCH
#if !TARGET_OS_SIMULATOR
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
if( !error ) {}
}];
#endif
}
#endif
}
}
#endif

Expand Down
9 changes: 9 additions & 0 deletions Ports/iOSPort/nativeSources/IOSNative.m
Original file line number Diff line number Diff line change
Expand Up @@ -10114,6 +10114,15 @@ JAVA_VOID com_codename1_impl_ios_IOSNative_sendLocalNotification___java_lang_Str
UNNotificationTrigger *trigger = cn1CreateNotificationTrigger(fireDate, repeatType);
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:notificationIdString content:content trigger:trigger];
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
// Request notification authorization on first schedule so local-notification-only
// apps still get prompted (the launch-time prompt was removed for issue #4876).
// The system shows the dialog at most once; later calls are a no-op.
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound + UNAuthorizationOptionBadge)
completionHandler:^(BOOL granted, NSError * _Nullable authError) {
if (authError != nil) {
CN1Log(@"Local notification authorization request failed: %@", authError.localizedDescription);
}
}];
cn1CancelScheduledLocalNotificationById(notificationIdString);
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
Expand Down
3 changes: 3 additions & 0 deletions docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ Only supported for App Store builds. See https://www.codenameone.com/developer-g
|ios.detectJailbreak
|true/false (defaults to false). When true, the iOS app will exit on launch if it detects that it's running on a jailbroken device.

|ios.notificationPermissionAtLaunch
|true/false (defaults to false). Backward-compatibility flag for the pre-issue-#4876 behavior. By default, the iOS notification permission prompt is deferred until the app calls `Push.register()` or schedules a `LocalNotification`, matching the Android flow and giving the developer a chance to display a rationale screen first. Set this hint to `true` to restore the legacy behavior in which the prompt fires automatically inside `application:didFinishLaunchingWithOptions:` as soon as the app launches. Existing apps relying on the prompt being shown at launch should set this to `true`; new apps should leave it disabled and trigger the prompt explicitly when they are ready to ask for permission.

|ios.applicationQueriesSchemes
|Comma separated list of url schemes that `canExecute` will respect on iOS. If the url scheme isn't mentioned here `canExecute` will return false starting with iOS 9. Notice that this collides with `ios.plistInject` when used with the `<key>LSApplicationQueriesSchemes</key>...` value so you should use one or the other. For example, to enable `canExecute` for a url like `myurl://xys` you can use: `myurl,myotherurl`

Expand Down
2 changes: 2 additions & 0 deletions docs/developer-guide/Push-Notifications.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ If the registration failed for some reason, the `pushRegistrationError()` callba

Notice that all this happens seamlessly behind the scenes when your app loads. You don't need to start any of this workflow.

NOTE: On iOS, the system permission prompt that asks the user to allow notifications is shown the first time you call `Display.getInstance().registerPush()` (or schedule a `LocalNotification`). It is no longer shown automatically when the app launches, so you can display your own rationale screen first and call `registerPush()` only after the user has agreed. This matches the Android flow. Apps that need the legacy launch-time prompt for backward compatibility can set the `ios.notificationPermissionAtLaunch=true` build hint.

==== Sending a push notification

Codename One provides a secure REST API for sending push notifications. As an HTTP API, it's language agnostic. You can send push notifications to your app using Java, PHP, Python, Ruby, or even by hand using something like curl. Each HTTP request can contain a push message and a list of device IDs to which the message should be sent. You don't need to worry about whether your app is running on Android, iOS, Windows, or the web. A single HTTP request can send a message to many devices at once.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,12 @@ public void usesClassMethod(String cls, String method) {
try(Writer fios = new OutputStreamWriter(Files.newOutputStream(appDelH.toPath()), StandardCharsets.UTF_8)) {
String str = new String(data, StandardCharsets.UTF_8);
str = str.replace("//#define CN1_INCLUDE_NOTIFICATIONS", "#define CN1_INCLUDE_NOTIFICATIONS");
if (request.getArg("ios.notificationPermissionAtLaunch", "false").equalsIgnoreCase("true")) {
// Restore pre-#4876 behavior: prompt for notification permission
// in didFinishLaunchingWithOptions instead of on first registerPush /
// sendLocalNotification call.
str = str.replace("//#define CN1_NOTIFICATION_PERMISSION_AT_LAUNCH", "#define CN1_NOTIFICATION_PERMISSION_AT_LAUNCH");
}
fios.write(str);
}

Expand Down
Loading