expo 对接极光推送

1,053 阅读5分钟

环境介绍

  1. 电脑 mac mini M2
  2. Xcode:Version 14.3.1
  3. expo 版本:49
  4. "jcore-react-native": "^2.1.5" "jpush-react-native": "^3.0.6"

极光账号注册

1. 我这边浏览器正常模式一直无法登录,我都是用无痕浏览器登录

jpush-react-native

readme说的还是挺清楚的,只是对于前端开发人员来说,可能有些不理解的地方,我这边讲step-by-step说明对接方式

详细操作

  1. 由于需改带动原生代码,所以需要prebuild
 npx expo prebuild

ios 对接

准备工作

  1. 配置证书, 参考极光文档,非常详细 docs.jiguang.cn/jpush/clien…
  2. 安装依赖 cd ios执行pod install(时间可能比较久,建议合理上网,已经install过的可先执行 pod deintegrate)
  3. 模拟器收不到消息,需要真机调试
  4. 下面大部分的代码在极光的example中都有,如有疑问,可以对比看下

修改代码

  1. 修改 ios/应用名/AppDelegate.mm,修改文件 备注标记为 添加内容,就是需要添加的代码 image.png
#import "AppDelegate.h"
// @generated begin react-native-quick-actions-import - expo prebuild (DO NOT MODIFY) sync-6ea4aa8a461f1aab4f2c38893cd59140deb974e4
#import "RNQuickActionManager.h"
// @generated end react-native-quick-actions-import

// 添加内容start
#import <RCTJPushModule.h>
#import <React/RCTBridge.h>
#import <React/RCTRootView.h>

#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif
// 添加内容end

#import <React/RCTBundleURLProvider.h>
#import <React/RCTLinkingManager.h>

// 添加内容start
@interface AppDelegate ()<JPUSHRegisterDelegate>
@end
// 添加内容end

@implementation AppDelegate

// @generated begin react-native-quick-actions-delegate - expo prebuild (DO NOT MODIFY) sync-c20e1981d7932e1a91e1d34dbf5c36e3ff230412
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded)) completionHandler {
  [RNQuickActionManager onQuickActionPress:shortcutItem completionHandler:completionHandler];
}
// @generated end react-native-quick-actions-delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.moduleName = @"main";

  // You can add your custom initial props in the dictionary below.
  // They will be passed down to the ViewController used by React Native.
  self.initialProps = @{};
  

   // 添加内容start APNS
  JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
  if (@available(iOS 12.0, *)) {
    // entity.types = JPAuthorizationOptionNone; //JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSou//nd|JPAuthorizationOptionProvidesAppNotificationSettings;
    entity.types = JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSound;
  }
  [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
   // 添加内容end 
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

// Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
}

// Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
  BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
  return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
}

// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
// - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
// {
//   return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
// }

// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
  return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
}

// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
// - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
// {
//   return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
// }

// 添加内容start
//注册 APNS 成功并上报 DeviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  [JPUSHService registerDeviceToken:deviceToken];
}

//iOS 7 APNS
- (void)application:(UIApplication *)application didReceiveRemoteNotification:  (NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  // iOS 10 以下 Required
  NSLog(@"iOS 7 APNS");
  [JPUSHService handleRemoteNotification:userInfo];
  [[NSNotificationCenter defaultCenter] postNotificationName:J_APNS_NOTIFICATION_ARRIVED_EVENT object:userInfo];
  completionHandler(UIBackgroundFetchResultNewData);
}

//iOS 10 前台收到消息
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center  willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
  NSDictionary * userInfo = notification.request.content.userInfo;
  if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
    // Apns
    NSLog(@"iOS 10 APNS 前台收到消息");
    [JPUSHService handleRemoteNotification:userInfo];
    [[NSNotificationCenter defaultCenter] postNotificationName:J_APNS_NOTIFICATION_ARRIVED_EVENT object:userInfo];
  }
  else {
    // 本地通知 todo
    NSLog(@"iOS 10 本地通知 前台收到消息");
    [[NSNotificationCenter defaultCenter] postNotificationName:J_LOCAL_NOTIFICATION_ARRIVED_EVENT object:userInfo];
  }
  //需要执行这个方法,选择是否提醒用户,有 Badge、Sound、Alert 三种类型可以选择设置
  completionHandler(UNNotificationPresentationOptionAlert);
}

//iOS 10 消息事件回调
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler: (void (^)(void))completionHandler {
  NSDictionary * userInfo = response.notification.request.content.userInfo;
  if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
    // Apns
    NSLog(@"iOS 10 APNS 消息事件回调");
    [JPUSHService handleRemoteNotification:userInfo];
    // 保障应用被杀死状态下,用户点击推送消息,打开app后可以收到点击通知事件
    [[RCTJPushEventQueue sharedInstance]._notificationQueue insertObject:userInfo atIndex:0];
    [[NSNotificationCenter defaultCenter] postNotificationName:J_APNS_NOTIFICATION_OPENED_EVENT object:userInfo];
  }
  else {
    // 本地通知
    NSLog(@"iOS 10 本地通知 消息事件回调");
    // 保障应用被杀死状态下,用户点击推送消息,打开app后可以收到点击通知事件
    [[RCTJPushEventQueue sharedInstance]._localNotificationQueue insertObject:userInfo atIndex:0];
    [[NSNotificationCenter defaultCenter] postNotificationName:J_LOCAL_NOTIFICATION_OPENED_EVENT object:userInfo];
  }
  // 系统要求执行这个方法
  completionHandler();
}

//自定义消息
- (void)networkDidReceiveMessage:(NSNotification *)notification {
  NSDictionary * userInfo = [notification userInfo];
  [[NSNotificationCenter defaultCenter] postNotificationName:J_CUSTOM_NOTIFICATION_EVENT object:userInfo];
}
// 添加内容end

//************************************************JPush end************************************************

@end

  1. 解决jpush sdk不支持arm64 问题 参考文档
  • xcode exclude arm64

    image.png

  • 修改 ios/Podfile

    image.png

    post_install do |installer|
      installer.pods_project.build_configurations.each do |config|
        config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
      end
    end
    
  1. 修改 ios/应用名/info.plist, 增加推送权限设置

           <key>UIBackgroundModes</key>
           <array>
                   <string>fetch</string>
                   <string>remote-notification</string>
           </array>
    

    image.png

  2. 在你的js层增加

      import JPush from 'jpush-react-native';
    
      useEffect(() => {
          JPush.init({ appKey: '极光应用的appKey', channel: 'dev', production: 1 });
        //连接状态
        const connectListener = (result: any) => {
          console.log('connectListener:' + JSON.stringify(result));
          // 获取registerID
          JPush.getRegistrationID((result) => console.log('registerID:' + JSON.stringify(result)));
        };
        JPush.addConnectEventListener(connectListener);
        //通知回调
        const notificationListener = (result: any) => {
          console.log('notificationListener:' + JSON.stringify(result));
          alert(JSON.stringify(result));
        };
        JPush.addNotificationListener(notificationListener);
        //本地通知回调
        const localNotificationListener = (result: any) => {
          console.log('localNotificationListener:' + JSON.stringify(result));
        };
        JPush.addLocalNotificationListener(localNotificationListener);
        //自定义消息回调
        const customMessageListener = (result: any) => {
          console.log('customMessageListener:' + JSON.stringify(result));
        };
        JPush.addCustomMessageListener(customMessageListener);
        //应用内消息回调
        JPush.pageEnterTo('HomePage'); // 进入首页,当页面退出时请调用 JPush.pageLeave('HomePage')
        const inappMessageListener = (result: any) => {
          console.log('inappMessageListener:' + JSON.stringify(result));
          alert(JSON.stringify(result));
        };
        JPush.addInappMessageListener(inappMessageListener);
        //tag alias事件回调
        const tagAliasListener = (result: any) => {
          console.log('tagAliasListener:' + JSON.stringify(result));
        };
        JPush.addTagAliasListener(tagAliasListener);
        //手机号码事件回调
        const mobileNumberListener = (result: any) => {
          console.log('mobileNumberListener:' + JSON.stringify(result));
        };
        JPush.addMobileNumberListener(mobileNumberListener);
      }, [])
    
  3. 用Xcode 打开workspace image.png

  4. buid 选择你的手机 image.png

平台发起推送测试

  1. 代码运行起来之后,会打印 registerId

    image.png

    WechatIMG29.jpg

  2. 收到消息

android 对接

安卓官方文档比较清晰,过程中我也没遇到什么坑,大家按照官方文档对接即可,下面也只是复制官方文档内容,方便大家看看

  1. 修改 build.gradle

    android {
          defaultConfig {
              applicationId "yourApplicationId"           //在此替换你的应用包名
              ...
              manifestPlaceholders = [
                      JPUSH_APPKEY: "yourAppKey",         //在此替换你的APPKey
                      JPUSH_CHANNEL: "yourChannel"        //在此替换你的channel
              ]
          }
      }
    
    dependencies {
          ...
          implementation project(':jpush-react-native')  // 添加 jpush 依赖
          implementation project(':jcore-react-native')  // 添加 jcore 依赖
      }
    
  2. setting.gradle

    include ':jpush-react-native'
    project(':jpush-react-native').projectDir = new File(rootProject.projectDir, '../node_modules/jpush-react-native/android')
    include ':jcore-react-native'
    project(':jcore-react-native').projectDir = new File(rootProject.projectDir, '../node_modules/jcore-react-native/android')
    
  3. AndroidManifest.xml

    <meta-data
            android:name="JPUSH_CHANNEL"
            android:value="${JPUSH_CHANNEL}" />
    <meta-data
            android:name="JPUSH_APPKEY"
            android:value="${JPUSH_APPKEY}" />    
    

ios证书配置

docs.jiguang.cn/jpush/clien…

参考文档

  1. github.com/jpush/jpush…
  2. docs.jiguang.cn/jpush/clien…
  3. github.com/jpush/jcore…
  4. drizzlesconsin.vercel.app/posts/xcode…
  5. juejin.cn/post/703703…
  6. github.com/jpush/jpush…