Discuz iOS应用开发 - bigApp iOS源码分析 - Remote Notification

源代码中没有发现Remote Notification的代码。
代码中有发现JPush相关的引用,但JPush库并没有引用。考虑可能是之前使用了JPush,但后面删除了。
BigApp源码中有JPush相关的PHP代码,因此考虑之前是使用JPush来实现iOS端的推送的。

Todo:

  • 调查JPush的使用
  • 调查JPush相关的PHP代码的使用

发现了一份最新的iOS客户端源码,带JPush相关的设置,fork到https://github.com/Inspirelife96/Discuz_IOS

新代码,从工程文件的变化来看,添加了JPush和SMS。
Diff了一下其他代码的变化,修正了发帖崩溃的代码,还有就是添加了分享的代码。

5/24 更新
看来bigApp确实使用了JPush,但最新的源码只是添加了JPush的注册代码,但并没有和用户绑定。

我们需要做的是:

  1. 向JPush Server注册Device Token。
  2. 绑定Device Token和用户的UserName (UserId?)
  3. 修改Badge的值(?根据推送来源分类?修改会困难?)

剩下的交给服务器端来做,需要根据UserName和JPushServer通信向指定的Device推送信息。

【极光推送】给指定用户发送消息

接下来就是各种配置了:
https://developer.apple.com官网要做的事:

  1. 申请app id (例如com.xxxxxxx.bigapp)。记得开Push Notification选项
  2. 配置Push Notificaiton的开发和生产证书。导出相应的.p12文件。
  3. 配置项目对应的开发和生产Provisioning 文件。

极光https://www.jiguang.cn需要做的事:

  1. 注册并添加一个新的应用
  2. 配置iOS的推送信息。需要用到上面的.p12文件。

具体的流程可以参考这里iOS最新极光推送详解

客户端开发
参考官方文档https://docs.jiguang.cn/jpush/client/iOS/ios_guide_new/,稍微做了下整合。

  1. 暂时是手动添加的,希望以后能改成cocoapods
  2. iOS8适配,开启Push Notification 功能。
  3. iOS9适配, 开启jpush.cn http白名单
  4. iOS10适配, UserNotifications

代码

  • 添加Delegate
1
2
3
@interface AppDelegate ()<JPUSHRegisterDelegate>

@end
  • 添加初始化APNs代码以及添加初始化JPush代码,适配iOS10,封装在下面这个函数并在

    *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions```调用
    1
    2


    • (void)setupJPush:(NSDictionary )launchOptions {
      JPUSHRegisterEntity
      entity = [[JPUSHRegisterEntity alloc] init];
      entity.types = JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSound;
      [self registerForRemoteNotification];
      [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];

      [JPUSHService setupWithOption:launchOptions appKey:@”56acc62e21172eafa0c54091”

                    channel:@"iOS"
           apsForProduction:NO
      advertisingIdentifier:nil];
      

      }

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      ```
      /**
      * 初始化UNUserNotificationCenter
      */
      - (void)registerForRemoteNotification {
      // iOS10 兼容
      if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
      // 使用 UNUserNotificationCenter 来管理通知
      UNUserNotificationCenter *uncenter = [UNUserNotificationCenter currentNotificationCenter];
      // 监听回调事件
      [uncenter setDelegate:self];
      //iOS10 使用以下方法注册,才能得到授权
      [uncenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert+UNAuthorizationOptionBadge+UNAuthorizationOptionSound)
      completionHandler:^(BOOL granted, NSError * _Nullable error) {
      [[UIApplication sharedApplication] registerForRemoteNotifications];
      //TODO:授权状态改变
      NSLog(@"%@" , granted ? @"授权成功" : @"授权失败");
      }];
      // 获取当前的通知授权状态, UNNotificationSettings
      [uncenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
      NSLog(@"%s\nline:%@\n-----\n%@\n\n", __func__, @(__LINE__), settings);
      /*
      UNAuthorizationStatusNotDetermined : 没有做出选择
      UNAuthorizationStatusDenied : 用户未授权
      UNAuthorizationStatusAuthorized :用户已授权
      */
      if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
      NSLog(@"未选择");
      } else if (settings.authorizationStatus == UNAuthorizationStatusDenied) {
      NSLog(@"未授权");
      } else if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) {
      NSLog(@"已授权");
      }
      }];
      }
      #pragma clang diagnostic push
      #pragma clang diagnostic ignored "-Wdeprecated-declarations"
      if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
      UIUserNotificationType types = UIUserNotificationTypeAlert |
      UIUserNotificationTypeBadge |
      UIUserNotificationTypeSound;
      UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];

      [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
      [[UIApplication sharedApplication] registerForRemoteNotifications];
      } else {
      UIRemoteNotificationType types = UIRemoteNotificationTypeBadge |
      UIRemoteNotificationTypeAlert |
      UIRemoteNotificationTypeSound;
      [[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
      }
      #pragma clang diagnostic pop
      }
  • 注册APNs成功并上报DeviceToken

1
2
3
4
5
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
/// Required - 注册 DeviceToken
[JPUSHService registerDeviceToken:deviceToken];
}
  • 其他回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
// Required
NSDictionary * userInfo = notification.request.content.userInfo;
if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[JPUSHService handleRemoteNotification:userInfo];
}
completionHandler(UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以选择设置
}

// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
// Required
NSDictionary * userInfo = response.notification.request.content.userInfo;
if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[JPUSHService handleRemoteNotification:userInfo];
}
completionHandler(); // 系统要求执行这个方法
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

// Required, iOS 7 Support
[JPUSHService handleRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

// Required,For systems with less than or equal to iOS6
[JPUSHService handleRemoteNotification:userInfo];
}

#pragma mark - 实现注册APNs失败接口(可选)
///=============================================================================
/// @name 实现注册APNs失败接口(可选)
///=============================================================================

/**
* also used in iOS10
*/
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"%s\n[无法注册远程提醒, 错误信息]\nline:%@\n-----\n%@\n\n", __func__, @(__LINE__), error);
}

测试log输出:成功在JPush Server上进行了注册

利用JPush的测试工具进行测试,可以看到收到了推送的消息

剩下的事:

  • 用户登录时或自动登录时将UserName绑定这个registrationID。
  • 用户退出登录时将UserName和这个registrationID解除绑定。
  • 其余的交给服务器端处理。现在不清楚BigApp插件的php代码是否已经可以顺利的进行推送。

服务器端开发
Todo