本文最后更新于:2025年6月28日 下午
前情提要 RN 现在的版本已经到了 0.80(2025-6-28),新架构已经是默认开启的了,官方也在制定逐步取消对旧架构的维护支持,在未来的版本中会移除旧架构,所以对于旧架构原先的 第三方库也要做对应的兼容处理。目前大部分流行热门的第三方库都已经得到了适配,但是一些冷门的,还是停留在旧的版本,或者以前的一些私有封装的 sdk 还停留在旧版本,所以很有必要研究一下如何适配。故此,选择了 极光推送的 jpush-react-native 作为练手。适配一个库是比较简单的,至少比从来开始写的工作量要少,我们只需要按照一定的格式规范 在旧架构的基础在做一些 “链接粘合”的工作即可。
Step - 1 为 package.json 添加 codegenConfig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 { "name" : "jpush-react-native" , "codegenConfig" : { "name" : "RNJPushSpec" , "type" : "modules" , "jsSrcsDir" : "specs" , "android" : { "javaPackageName" : "cn.jiguang.plugins.push" } } }
codegen : 为你的 Turbo Native Module 生成链接 到 RN 链接模版代码的一个工作。
“name”: “RNJPushSpec”, 这个生成模版代码的文件名字,这个在 iOS 中用到
1 2 3 4 5 6 7 8 9 10 11 #ifdef RCT_NEW_ARCH_ENABLED #import <RNJPushSpec/RNJPushSpec.h> @interface RCTJPushModule: NSObject <NativeJpushSpec>#else @interface RCTJPushModule : RCTEventEmitter <RCTBridgeModule> @end
Step -2 编写 specs 规范文件 我在 specs 目录下的 创建了 NativeJpush.ts。可以用 ts 或者 flow 编写,也是有模版的,这里定义的是,原生暴露出来的 js 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import type { TurboModule } from "react-native" ;import { TurboModuleRegistry } from "react-native" ;export interface Spec extends TurboModule { setDebugMode : (enable: boolean ) => void ; isPushStopped : (cb: () => void ) => void ; setChannel : (obj: Object ) => void ; }export default TurboModuleRegistry .getEnforcing <Spec >("JPushModule" );
Android codegen 会根据这个文件生成模版代码文件 NativeJpushSpec(位于库中 android/build/generated/codegen ),我们会继承覆盖实现这个抽象类中的方法
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 package cn.jiguang.plugins.push;import com.facebook.proguard.annotations.DoNotStrip;import com.facebook.react.bridge.Callback;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.bridge.ReactContextBaseJavaModule;import com.facebook.react.bridge.ReactMethod;import com.facebook.react.bridge.ReadableMap;import com.facebook.react.turbomodule.core.interfaces.TurboModule;import javax.annotation.Nonnull;public abstract class NativeJpushSpec extends ReactContextBaseJavaModule implements TurboModule { public static final String NAME = "JPushModule" ; public NativeJpushSpec (ReactApplicationContext reactContext) { super (reactContext); } @Override public @Nonnull String getName () { return NAME; } @ReactMethod @DoNotStrip public abstract void setDebugMode (boolean enable) ; @ReactMethod @DoNotStrip public abstract void init () ; }
Step-3 Android 改造 改造后的目录结构如下
3-1 grade.build 文件的改造 主要是 根据是否判断新旧架构,引入相关的依赖和,添加选择对应的 源 java 目录
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 apply plugin: 'com.android.library'+ def isNewArchitectureEnabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" }+ if (isNewArchitectureEnabled()) { + apply plugin: 'com.facebook.react' +} def safeExtGet(prop, fallback) { rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback } android { compileSdkVersion safeExtGet('compileSdkVersion', 34) namespace 'cn.jiguang.plugins.push' defaultConfig { minSdkVersion safeExtGet('minSdkVersion', 23) targetSdkVersion safeExtGet('targetSdkVersion', 34) versionCode 1 versionName "1.0"+ buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()) }+ sourceSets { + main { + if (isNewArchitectureEnabled()) { + java.srcDirs += ['src/newarch'] + } else { + java.srcDirs += ['src/oldarch'] + } + } + } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.facebook.react:react-native:+' }
3-2 JPushModuleImpl 文件的改造。 JPushModuleImpl 文件是由 JPushModule 改造而来,是真正实现功能的地方。
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 54 55 56 57 58 59 60 61 62 package cn.jiguang.plugins.push;import android.app.NotificationChannel;import android.app.NotificationManager;import android.net.Uri;import android.os.Build;import android.app.Activity;import android.app.Application;import android.os.Bundle;import android.text.TextUtils;import android.util.Log;import com.facebook.react.bridge.Arguments;import com.facebook.react.bridge.Callback;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.bridge.ReactContextBaseJavaModule;import com.facebook.react.bridge.ReactMethod;import com.facebook.react.bridge.ReadableArray;import com.facebook.react.bridge.ReadableMap;import com.facebook.react.bridge.ReadableNativeMap;import com.facebook.react.bridge.WritableMap;import org.json.JSONObject;import java.util.HashMap;import java.util.HashSet;import java.util.Set;import java.lang.*;import cn.jiguang.plugins.push.common.JConstants;import cn.jiguang.plugins.push.common.JLogger;import cn.jiguang.plugins.push.helper.JPushHelper;import cn.jiguang.plugins.push.receiver.JPushBroadcastReceiver;import cn.jpush.android.api.BasicPushNotificationBuilder;import cn.jpush.android.api.JPushInterface;import cn.jpush.android.data.JPushCollectControl;import cn.jpush.android.data.JPushLocalNotification;public class JPushModuleImpl { public static ReactApplicationContext reactContext; public static boolean isAppForeground = false ; public static final String NAME = "JPushModule" ; public JPushModuleImpl (ReactApplicationContext reactApplicationContext) { reactContext = reactApplicationContext; } public void setDebugMode (boolean enable) { JPushInterface.setDebugMode(enable); JLogger.setLoggerEnable(enable); } }
3-3 JPushPackage 文件的改造。 这个文件,也是模版代码,照参考的改就好了。
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 package cn.jiguang.plugins.push;import androidx.annotation.Nullable;import com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.module .model.ReactModuleInfo;import com.facebook.react.module .model.ReactModuleInfoProvider;import com.facebook.react.TurboReactPackage;import com.facebook.react.uimanager.ViewManager;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.HashMap;import java.util.Map;public class JPushPackage extends TurboReactPackage { @Nullable @Override public NativeModule getModule (String name, ReactApplicationContext reactContext) { if (name.equals(JPushModuleImpl.NAME)) { return new JPushModule (reactContext); } else { return null ; } } @Override public ReactModuleInfoProvider getReactModuleInfoProvider () { return () -> { final Map<String, ReactModuleInfo> moduleInfos = new HashMap <>(); boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; moduleInfos.put( JPushModuleImpl.NAME, new ReactModuleInfo ( JPushModuleImpl.NAME, JPushModuleImpl.NAME, false , false , true , false , isTurboModule )); return moduleInfos; }; } }
step-3. 新架构 newarch 目录下的 JPushModule.java 继承实现 NativeJpushSpec 类中的方法,实例化 JPushModuleImpl 类 作为代理,调用真正的实现方式
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 package cn.jiguang.plugins.push;import android.app.NotificationChannel;import android.app.NotificationManager;import android.net.Uri;import android.os.Build;import android.app.Activity;import android.app.Application;import android.os.Bundle;import android.text.TextUtils;import android.util.Log;import com.facebook.react.bridge.Arguments;import com.facebook.react.bridge.Callback;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.bridge.ReactContextBaseJavaModule;import com.facebook.react.bridge.ReactMethod;import com.facebook.react.bridge.ReadableArray;import com.facebook.react.bridge.ReadableMap;import com.facebook.react.bridge.ReadableNativeMap;import com.facebook.react.bridge.WritableMap;import com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.Promise;import com.facebook.react.bridge.ReactContext;import org.json.JSONObject;import java.util.HashMap;import java.util.HashSet;import java.util.Set;import java.lang.*;import cn.jiguang.plugins.push.common.JConstants;import cn.jiguang.plugins.push.common.JLogger;import cn.jiguang.plugins.push.helper.JPushHelper;import cn.jiguang.plugins.push.receiver.JPushBroadcastReceiver;import cn.jpush.android.api.BasicPushNotificationBuilder;import cn.jpush.android.api.JPushInterface;import cn.jpush.android.data.JPushCollectControl;import cn.jpush.android.data.JPushLocalNotification;public class JPushModule extends NativeJpushSpec { private final JPushModuleImpl delegate; public JPushModule (ReactApplicationContext reactContext) { super (reactContext); delegate = new JPushModuleImpl (reactContext); } @Override public String getName () { return JPushModuleImpl.NAME; } @Override public void setDebugMode (boolean enable) { delegate.setDebugMode(enable); } @Override public void init () { delegate.init(); } }
step-4 旧架构 oldarch 下的 JPushModule.java 此文件为 原旧架构的 JPushModule,不同的是,实例化了 JPushModuleImpl 作为了代理实现各个方法
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 package cn.jiguang.plugins.push;import android.app.NotificationChannel;import android.app.NotificationManager;import android.net.Uri;import android.os.Build;import android.app.Activity;import android.app.Application;import android.os.Bundle;import android.text.TextUtils;import android.util.Log;import com.facebook.react.bridge.Arguments;import com.facebook.react.bridge.Callback;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.bridge.ReactContextBaseJavaModule;import com.facebook.react.bridge.ReactMethod;import com.facebook.react.bridge.ReadableArray;import com.facebook.react.bridge.ReadableMap;import com.facebook.react.bridge.ReadableNativeMap;import com.facebook.react.bridge.WritableMap;import org.json.JSONObject;import java.util.HashMap;import java.util.HashSet;import java.util.Set;import java.lang.*;import cn.jiguang.plugins.push.common.JConstants;import cn.jiguang.plugins.push.common.JLogger;import cn.jiguang.plugins.push.helper.JPushHelper;import cn.jiguang.plugins.push.receiver.JPushBroadcastReceiver;import cn.jpush.android.api.BasicPushNotificationBuilder;import cn.jpush.android.api.JPushInterface;import cn.jpush.android.data.JPushCollectControl;import cn.jpush.android.data.JPushLocalNotification;public class JPushModule extends ReactContextBaseJavaModule { private final JPushModuleImpl delegate; public JPushModule (ReactApplicationContext reactContext) { super (reactContext); delegate = new JPushModuleImpl (reactContext); } @Override public String getName () { return JPushModuleImpl.NAME; } @ReactMethod public void setDebugMode (boolean enable) { delegate.setDebugMode(enable); } @ReactMethod public void init () { delegate.init(); } @ReactMethod public void stopPush () { delegate.stopPush(); } @ReactMethod public void resumePush () { delegate.resumePush(); } @ReactMethod public void isPushStopped (Callback callback) { delegate.isPushStopped(callback); } @ReactMethod public void setChannel (ReadableMap readableMap) { delegate.setChannel(readableMap); } @ReactMethod public void setChannelAndSound (ReadableMap readableMap) { delegate.setChannelAndSound(readableMap); } @ReactMethod public void setLinkMergeEnable (boolean enable) { delegate.setLinkMergeEnable(enable); } @ReactMethod public void setSmartPushEnable (boolean enable) { delegate.setSmartPushEnable(enable); } @ReactMethod public void setDataInsightsEnable (boolean enable) { delegate.setDataInsightsEnable(enable); } @ReactMethod public void setGeofenceEnable (boolean enable) { delegate.setGeofenceEnable(enable); } @ReactMethod public void setCollectControl (ReadableMap readableMap) { delegate.setCollectControl(readableMap); } @ReactMethod public void setBadgeNumber (ReadableMap readableMap) { delegate.setBadgeNumber(readableMap); } }
Step 4 iOS 改造 Step 4-1 JPushRN.podspec 文件的改造 cocoapods 的依赖配置文件 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 require 'json' pjson = JSON.parse(File.read('package.json'))+ fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' Pod::Spec.new do |s| s.name = "JPushRN" s.version = pjson["version"] s.homepage = pjson["homepage"] s.summary = pjson["description"] s.license = pjson["license"] s.author = pjson["author"] s.platforms = { :ios => "11.0" } s.frameworks = 'UIKit','CFNetwork','CoreFoundation','CoreTelephony','SystemConfiguration','CoreGraphics','Foundation','Security' s.source = { :git => "https://github.com/jpush/jpush-react-native.git", :tag => "#{s.version}" } s.source_files = "ios/**/*.{h,m,mm,swift}" s.preserve_paths = "*.js" s.weak_frameworks = 'UserNotifications' s.libraries = 'z','resolv' s.vendored_frameworks = "ios/RCTJPushModule/*.xcframework"+ if fabric_enabled + # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0. + # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/+ new_architecture.rb#L79. + if respond_to?(:install_modules_dependencies, true) + install_modules_dependencies(s) + else + # just for backward compatibility: if React Native version <= 0.70.x + s.compiler_flags = "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32 -DRCT_NEW_ARCH_ENABLED=1" + s.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", + "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" + } + s.dependency 'React-Core' + s.dependency "React-Codegen" + s.dependency "React-RCTFabric" + s.dependency "RCT-Folly" + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "ReactCommon/turbomodule/core" + end + else + s.dependency 'React-Core' + end end
step 4-1 RCTJPushModule.h 文件改造 1 2 3 4 5 6 7 8 9 10 11 12 + #ifdef RCT_NEW_ARCH_ENABLED + #import <RNJPushSpec/RNJPushSpec.h> + /*注意这里 NativeJpushSpec 是为 specs 目录下文件的名字 */ + @interface RCTJPushModule: NSObject <NativeJpushSpec> + #else + @interface RCTJPushModule : RCTEventEmitter <RCTBridgeModule> + endif + @end
step-4-2 RCTJPushModule.m 文件 改为 RCTJPushModule.mm 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + #if RCT_NEW_ARCH_ENABLED + #import <RNJPushSpec/RNJPushSpec.h> + #endif + # pragma mark - New Architecture + #if RCT_NEW_ARCH_ENABLED + - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params + { + // 注意 NativeJpushSpecJSI 这个名字 NativeJpushSpe+JSI 这是由codegen 生成的 + return std::make_shared<facebook::react::NativeJpushSpecJSI>(params); + } #endif
兼容感想 对 原生的各种报错一脸懵逼,但好在有 ai 的答疑,也解决了不少的问题,这次对新架构更多了一些了解。
参考链接