phonegap / phonegap-plugin-push

Register and receive push notifications
MIT License
1.94k stars 1.91k forks source link

ios voip notifications sound not worked as expected #2385

Open EugeneSnihovsky opened 6 years ago

EugeneSnihovsky commented 6 years ago

Hello guys!

Actual Behaviour

I init voip notifications on my real device (iPad, iOS 10.3.3) like this

this._pushInstance = PushNotification.init({ ios: { voip: true } });

And found strange behaviour in voip notifications:

Sended payload:

payload.aps = {
    alert: 'test message',
    sound: 'test_sound.aiff' // file test_sound.aiff added in Xcode to Resources, after compiling it located in root of app content folder
}

or

payload.aps = {
    alert: 'test message',
    sound: 'default'
}

I receive this notifications (see text field and sound field in it), but without any sounds.

Possible solution

After some researches I found this solution. According to it I changed in Xcode => Classes two files

AppDelegate.h

before

#import <Cordova/CDVViewController.h>
#import <Cordova/CDVAppDelegate.h>

@interface AppDelegate : CDVAppDelegate {}

@end

after

#import <Cordova/CDVViewController.h>
#import <Cordova/CDVAppDelegate.h>
#import <UserNotifications/UserNotifications.h>

@interface AppDelegate : CDVAppDelegate {}

@end
AppDelegate.m

before

#import "AppDelegate.h"
#import "MainViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    self.viewController = [[MainViewController alloc] init];
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

@end

after

#import "AppDelegate.h"
#import "MainViewController.h"
#import <UserNotifications/UserNotifications.h>

#define SYSTEM_VERSION_GRATERTHAN_OR_EQUALTO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

@interface AppDelegate() <UNUserNotificationCenterDelegate>

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    self.viewController = [[MainViewController alloc] init];

    [self registerForRemoteNotification];

    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (void)registerForRemoteNotification {
    if(SYSTEM_VERSION_GRATERTHAN_OR_EQUALTO(@"10.0")) {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        center.delegate = self;
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
            if( !error ){
                [[UIApplication sharedApplication] registerForRemoteNotifications];
            }
        }];
    }
    else {
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    }
}

//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
    NSLog(@"User Info : %@",notification.request.content.userInfo);
    completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}

//Called to let your app know which action was selected by the user for a given notification.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
    NSLog(@"User Info : %@",response.notification.request.content.userInfo);
    completionHandler();
}

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
    NSLog(@"Error in registration. Error: %@", err);

}

@end

Changes in app after this fixes

  1. On first launch app begin to ask permissions for notifications
  2. sound field in payload begin to work correctly as expected (device play custom and default music during notification)
  3. for now device receive voip notification from app only if app is fully closed
  4. on each device registration device token is always different (according to docs this is normal behaviour). Without fixes device token is always the same (differs only for release and debug app versions)

So problem is solved but how can I automate fixes for AppDelegate.(h|m) files? Can this be implemented in new versions of your plugin or I have a specific case?

macdonst commented 6 years ago

@EugeneSnihovsky seems like this would be fixed by #2266. Can you give that PR a review and try it out locally to see if it fixes your problem?

EugeneSnihovsky commented 6 years ago

@macdonst I implemented locally in Xcode changes for all 4 files from this request, relaunch app on my device and it not helped. Notifications worked but without sound. Maybe I missed something?

Additional info:
  1. Without my fixes (original plugin version and version with 2266 fixes) using received token from plugin, I can send notification with Production VoIP Services Certificate

    Establish connectivity between your notification server, the Apple Push Notification service sandbox, and production environment to alert background VoIP apps of incoming activity. A separate certificate is required for each app you distribute.

    It creates from apple developer => certificates => add icon

  2. With fixes from my topic I receive other token that can't be used with certificate from 1. I need Apple Push Notification service SSL Certificates

    To configure push notifications for this iOS App ID, a Client SSL Certificate that allows your notification server to connect to the Apple Push Notification Service is required. Each iOS App ID requires its own Client SSL Certificate. Manage and generate your certificates below.

    It creates from apple developer => Identifiers => my app id => edit => Push Notifications => Create Certificate. And all works correct

NOTE: my fixes has some bug and I receive correct token not in cordova on registration callback, this callback still return token that work as in 1. Correct token I receive from Xcode log

Unexpected call to didRegisterForRemoteNotificationsWithDeviceToken, ignoring: <1d32b314 48060e21 18b8f001 8bc1da0f 3d92ee23 89db0050 23b4f022 5bb5f6cf>