ReactNative原生Android交互

在開發中,我們經常遇到需要和原生交互的場景,ReactNative已經給我們預置了相關接口,接下來簡單使用一下吧。

1.初始化一個空項目,用作示例:
react-native init Demo
cd Demo
react-native run-android
2.用Android Studio編寫JAVA代碼:

新建ToastModule類繼承ReactContextBaseJavaModule,並實現父類抽象方法,其中getName()方法的返回值即是當前模塊的名字。

ReactNative調用:NativeModules.TestMode

public class ToastModule extends ReactContextBaseJavaModule{


    public ToastModule(@Nonnull ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Nonnull
    @Override
    public String getName() {
        return "TestMode";
    }
    
}

重寫public Map<String, Object> getConstants() 方法,提供變量供ReactNative使用。

ReactNative調用:NativeModules.TestMode.SHORT

    private static final String DURATION_SHORT_KEY = "SHORT";
    private static final String DURATION_LONG_KEY = "LONG";

    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
        constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
        return constants;
    }

提供方法供ReactNative使用,需要添加@ReactMethod註解。

ReactNative調用:NativeModules.TestMode.showToast("測試輸出", NativeModules.TestMode.SHORT)

    @ReactMethod
    public void showToast(String message, int duration) {
        Toast.makeText(getReactApplicationContext(), message, duration).show();
    }

提供回調方法供ReactNative使用,需要添加@ReactMethod註解,回調函數使用ReactNative提供的Callback。

ReactNative調用:NativeModules.TestMode.showCall((name, age, isMan) => {console.log(name + "+" + age + "+" + isMan)})

    @ReactMethod
    public void showCall(Callback callback) {
        callback.invoke("hello", 123, false);
    }

提供發送事件的方法供ReactNative使用,需要添加@ReactMethod註解。

ReactNative調用:this.call = DeviceEventEmitter.addListener('event', (data) => {console.log("收到消息:", data) });

    @ReactMethod
    public void sendEvent() {
        getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("event", count);
        count++;
    }

模塊監聽Activity生命週期,需要實現LifecycleEventListener接口。

    reactContext.addActivityEventListener(this);

    @Override
    public void onHostResume() {

    }

    @Override
    public void onHostPause() {

    }

    @Override
    public void onHostDestroy() {

    }

模塊監聽onActivityResult,需要實現ActivityEventListener接口。

    reactContext.addLifecycleEventListener(this);

    @Override
    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {

    }

    @Override
    public void onNewIntent(Intent intent) {

    }
3.完整代碼:

App.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */
import { NativeModules, DeviceEventEmitter } from "react-native";
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import TestRN from "./TestRN";


const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
  android:
    'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
});

type Props = {};
export default class App extends Component<Props> {

  constructor(props) {
    super(props)
    this.state = {
      one: '',
      two: '',
    }
  }


  componentDidMount() {
    this.call = DeviceEventEmitter.addListener('event', (data) => {
      console.log("收到消息:", data)
      this.setState({ one: data })
    });

    TestRN.showToast("測試輸出", TestRN.SHORT)
    TestRN.showCall((name, age, isMan) => {
      console.log(name + "+" + age + "+" + isMan)
      this.setState({ two: name + "+" + age + "+" + isMan })
    })
  }

  componentWillMount() {
    this.call && this.call.remove()
  }


  render() {
    return (
      <TouchableOpacity style={styles.container} onPress={() => {
        TestRN.sendEvent()
      }}>
        <Text style={styles.welcome}>Demo測試</Text>
        <Text style={styles.instructions}>{this.state.one}</Text>
        <Text style={styles.instructions}>{this.state.two}</Text>
      </TouchableOpacity>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

TestRN.js

import { NativeModules } from "react-native";
export default NativeModules.TestMode;

ToastModule.java

package com.demo;

import android.app.Activity;
import android.content.Intent;
import android.widget.Toast;

import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nonnull;

public class ToastModule extends ReactContextBaseJavaModule implements LifecycleEventListener, ActivityEventListener {
    private static final String DURATION_SHORT_KEY = "SHORT";
    private static final String DURATION_LONG_KEY = "LONG";
    private int count = 12580;

    public ToastModule(@Nonnull ReactApplicationContext reactContext) {
        super(reactContext);
        reactContext.addActivityEventListener(this);
        reactContext.addLifecycleEventListener(this);
    }

    @Nonnull
    @Override
    public String getName() {
        return "TestMode";
    }

    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
        constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
        return constants;
    }

    @ReactMethod
    public void showToast(String message, int duration) {
        Toast.makeText(getReactApplicationContext(), message, duration).show();
    }

    @ReactMethod
    public void showCall(Callback callback) {
        callback.invoke("hello", 123, false);
    }

    @ReactMethod
    public void sendEvent() {
        getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("event", count);
        count++;
    }


    @Override
    public void onHostResume() {

    }

    @Override
    public void onHostPause() {

    }

    @Override
    public void onHostDestroy() {

    }

    @Override
    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {

    }

    @Override
    public void onNewIntent(Intent intent) {

    }
}

ToastPackage.java

package com.demo;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.annotation.Nonnull;

public class ToastPackage implements ReactPackage {

    @Nonnull
    @Override
    public List<NativeModule> createNativeModules(@Nonnull ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new ToastModule(reactContext));
        return modules;
    }

    @Nonnull
    @Override
    public List<ViewManager> createViewManagers(@Nonnull ReactApplicationContext reactContext) {

        return Collections.emptyList();
    }
}

MainApplication.java

package com.demo;

import android.app.Application;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

import java.util.Arrays;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
            return Arrays.<ReactPackage>asList(
                    new MainReactPackage(),
                    new ToastPackage()
            );
        }

        @Override
        protected String getJSMainModuleName() {
            return "index";
        }
    };

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        SoLoader.init(this, /* native exopackage */ false);
    }
}

4.順序梳理:
  • 1.編寫待調用的JAVA Module類,通過@ReactMethod註解暴露外部調用的方法。
  • 2.編寫ReactPackage類,並在createNativeModules方法中添加Module中的類。
  • 3.在MainApplication中getPackages()中註冊上面的ReactPackage類。
  • 4.編譯apk,並在ReactNative中調用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章