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;
  • 文件目錄:


    工程目錄.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<OrgTreeNode> 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<TopologyLayout> {
    @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<OrgTreeNode> nodes =gson.fromJson(dataResource.toString(), new TypeToken<ArrayList<OrgTreeNode>>() {}.getType());
            layout.setMachineList(nodes);
        }
    }
}
//MyReactPackage
public class MyReactPackage implements ReactPackage {

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.<ViewManager>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(
      <View style={styles.fullScreen}>
        <TopologyView
          style={styles.fullScreen}
          dataResource={this.props.dataResource}
          onItemClick={this.onItemClick.bind(this)}
        />
      </View>
    )
  }
  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以消息通知機制發送事件。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容