ReactNative和原生的相互调用

  • ReactNative?
  • 是Facebook开源的跨平台移动应用开发框架
  • ReactNative的导入
  • iOS使用CocoaPods
  • android使用Gradle
  • 在原生应用中嵌入RN
  • iOS:从RN中加载的view添加到viewcontroller
    • RNViewController封装:
//  RNViewController.h
@interface RNViewController : UIViewController
@property (nonatomic, copy) NSString *jsBundleURLForBundleRoot;
@property (nonatomic, copy) NSString *moduleName;
@property (nonatomic, copy) NSDictionary *props;
//  RNViewController.m
@implementation RNViewController
-(void)viewDidLoad {
      [super viewDidLoad];  
      NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:self.jsBundleURLForBundleRoot fallbackResource:nil];
      RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:self.moduleName
                                               initialProperties:self.props
                                                   launchOptions:nil];
      self.view = rootView;
}
@end
  • RNViewController调用:
RNViewController *rnViewController = [[RNViewController alloc] init];
    rnViewController.jsBundleURLForBundleRoot = @"reactNative/pages/IndexPage";
    rnViewController.moduleName = @"IndexPage";
    rnViewController.props = props;
    [UIApplication sharedApplication].keyWindow.rootViewController = rnViewController;
  • 文件目录:


    ReactNative和原生的相互调用_第1张图片
    工程目录.png
  • android:从RN中加载的view添加到activity
    • RNActivity封装
//RNActivity
public class RNActivity extends BaseActivity implements DefaultHardwareBackBtnHandler {
    public static final String MODULE_NAME_KEY = "module_name_key";
    public static final String PARAM_KEY = "param_key";
    public static final String TITLE_KEY = "title_key";
    private ReactInstanceManager mReactInstanceManager;
    private ReactRootView mReactRootView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rn);

        String moduleName = getIntent().getStringExtra(MODULE_NAME_KEY);
        Bundle param = getIntent().getBundleExtra(PARAM_KEY);

        mReactInstanceManager = MyApplication.reactInstanceManager();
        mReactRootView = new ReactRootView(this);
        mReactRootView.startReactApplication(mReactInstanceManager,
                moduleName, param);
        mContainer.addView(mReactRootView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
      }
}
//MyApplication
public class MyApplication extends Application {
    private static ReactInstanceManager mReactInstanceManager;
    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(this)
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("reactNative/pages/IndexPage")
                .addPackage(new MainReactPackage())
                .addPackage(new MyReactPackage())//用于导出包
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
    }
    public static ReactInstanceManager reactInstanceManager() {
        return mReactInstanceManager;
    }
}
- RNActivity调用:
        Intent intent = new Intent(this, RNActivity.class);
        intent.putExtra(RNActivity.MODULE_NAME_KEY, "IndexPage");
        intent.putExtra(RNActivity.PARAM_KEY, bundle);
        startActivity(intent);
  • RN中使用原生控件:
  • iOS:
//  TopologyView.h
@interface TopologyView : UIView
@property (nonatomic, strong) NSArray *dataResource;
@property (nonatomic, copy) RCTBubblingEventBlock onItemClick;
@end
// TopologyView.m
//数据源
-(void)setDataResource:(NSArray *)machineArr{
      //添加子view  
}
//RN传递来的事件
-(void)onItemClickInRN{
  self.onItemClick(@{@"index":@(_selectedMachineView.tag)});
}
//TopologyViewManager.h
@interface TopologyViewManager : RCTViewManager
@end
//TopologyViewManager.m
@implementation TopologyViewManager
RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(dataResource, NSArray)
RCT_EXPORT_VIEW_PROPERTY(onItemClick, RCTBubblingEventBlock)
-(UIView *)view
{
  TopologyView *view = [[TopologyView alloc] init];
  return view;
}
@end
  • android:
//TopologyLayout
public class TopologyLayout extends RelativeLayout{

    public void setMachineList(ArrayList machineList){
        //添加子view 
    }

    private void onReceiveNativeEvent(int index){
        WritableMap event = Arguments.createMap();
        event.putInt("index", index);
        ReactContext reactContext = (ReactContext)getContext();
        reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("onItemClick", event);
    }
}
//TopologyLayoutManager
public class TopologyLayoutManager  extends SimpleViewManager {
    @Override
    public String getName() {
        return "TopologyView";
    }

    @Override
    protected TopologyLayout createViewInstance(ThemedReactContext themedReactContext) {
        return new TopologyLayout(themedReactContext);
    }

    @ReactProp(name = "dataResource")
    public void setDataResource(TopologyLayout layout,  ReadableArray dataResource){
        if (dataResource!=null){
            Gson gson = new GsonBuilder().create();
            ArrayList nodes =gson.fromJson(dataResource.toString(), new TypeToken>() {}.getType());
            layout.setMachineList(nodes);
        }
    }
}
//MyReactPackage
public class MyReactPackage implements ReactPackage {

    @Override
    public List createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.asList(
                new TopologyLayoutManager()
        );
    }
}

注意:android导出需要在ReactInstanceManager初始化的时候addPackage(new MyReactPackage())

  • RN中调用:
//TopologyView.js
import { requireNativeComponent, View } from 'react-native';
module.exports = requireNativeComponent('TopologyView', null);
//TopologyPage.js
import TopologyView from '../nativeModules/TopologyView'
export default class TopologyPage extends React.Component {
  componentDidMount() {
    this.onTopologyViewItemClickListener = DeviceEventEmitter.addListener('onItemClick',(event) => {
      //android点击事件
    })
  }
  componentWillUnmount() {
    this.onTopologyViewItemClickListener.remove();
  }
  render(){
    return(
      
        
      
    )
  }
  onItemClick(event: Event) {
     //iOS点击事件
  }
}
  • 总结:
  • iOS和android嵌入RN都是指定文件URL和参数即可,android稍微复杂一点,需要用ReactInstanceManager初始化。
  • iOS导出原生模块需要创建Manager继承RCTViewManager,然后在Manager.m中用RCT_EXPORT_MODULE宏即可导出。
    android还需要新建ReactPackage子类,在createViewManagers中添加Manager,然后在ReactInstanceManager初始化的时候添加该ReactPackage子类才可供RN调用。
  • iOS的事件传递通过props以block代码块形式传入。
    android以消息通知机制发送事件。

你可能感兴趣的:(ReactNative和原生的相互调用)