React Native 原生模块开发教程:Toast、Log 与回调函数

Viewed 0

React Native 原生模块开发

在 React Native 开发中,有时应用需要访问平台原生 API,但 React Native 可能尚未提供相应模块;或者您希望复用现有 Java 代码,而不是用 JavaScript 重新实现;又或者需要实现高性能、多线程的功能,如图片处理或数据库操作。React Native 允许开发者编写原生代码来扩展功能,并访问全部平台能力。虽然这不是日常开发中的常见需求,但掌握这一技能非常重要。本文将指导您如何创建原生模块,并以 Toast 消息和 Log 日志为例,同时介绍回调函数的使用方法。

一、Toast 和 Log 模块

本指南以 Android 平台为例,展示如何从 JavaScript 调用原生 Toast 消息(屏幕下方弹出通知)和打印 Logcat 日志。

1. 创建原生模块类

首先,在项目源码目录中创建原生模块类:ToastModule.javaLogModule.java。原生模块是一个继承 ReactContextBaseJavaModule 的 Java 类,用于实现 JavaScript 所需功能。

ToastModule.java 类:

public class ToastModule1 extends ReactContextBaseJavaModule {
    private static final String DURATION_SHORT_KEY = "SHORT";
    private static final String DURATION_LONG_KEY = "LONG";

    public ToastModule1(ReactApplicationContext reactContext) {
        super(reactContext);
    }

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

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

    @ReactMethod
    public void show(final String message, final int duration) {
        UiThreadUtil.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getReactApplicationContext(), message, duration).show();
            }
        });
    }
}

LogModule.java 类:

public class LogModule extends ReactContextBaseJavaModule {
    public LogModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

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

    @ReactMethod
    public void d(String tag, String msg) {
        Log.d(tag, msg);
    }
}

2. 注册模块

接下来,在应用的 Package 类中注册这些模块,以便 JavaScript 可以访问。创建一个 AppReactPackage.java 类,并在 createNativeModules 方法中添加模块。

AppReactPackage.java 类:

public class AppReactPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new LogModule(reactContext));
        modules.add(new ToastModule1(reactContext));
        return modules;
    }

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

然后,在 MainActivity.java 文件中注册这个 Package,确保 React Native 实例管理器包含它。

MainActivity.java 文件(部分代码):

public class MainActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .addPackage(new AppReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        mReactRootView.startReactApplication(mReactInstanceManager, "MyAwesomeApp", null);
        setContentView(mReactRootView);
    }
    // 其他生命周期方法省略
}

3. 创建 JavaScript 封装模块

为了方便 JavaScript 调用,通常将原生模块封装成 JavaScript 模块。在应用根目录下创建 ToastAndroid.js 文件。

ToastAndroid.js 文件:

var { NativeModules } = require('react-native');
module.exports = NativeModules.ToastAndroid;

4. 在 JavaScript 中调用 API

最后,在 index.android.js 文件中调用原生模块功能。

index.android.js 文件:

'use strict';
var React = require('react');
var ReactNative = require('react-native');
var ToastAndroid = require('./ToastAndroid');
var {
    Text,
    View,
    StyleSheet,
    AppRegistry,
    NativeModules,
} = ReactNative;

var Log1 = NativeModules.Log;
Log1.d("Log1", "LOG");
ToastAndroid.show("Toast1", ToastAndroid.SHORT);

class MyAwesomeApp extends React.Component {
    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.hello}>Hello, World</Text>
            </View>
        );
    }
}

var styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
    },
    hello: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10,
    },
});

AppRegistry.registerComponent('MyAwesomeApp', () => MyAwesomeApp);

运行应用后,可以在 LogCat 中查看日志输出,并看到 Toast 消息显示。

二、回调函数

原生模块还支持回调函数参数,允许将结果从 Java 层返回给 JavaScript 层。这在处理异步操作(如网络请求)时非常有用。

1. 创建带回调的原生模块

创建一个 NetModule.java 类,继承 ReactContextBaseJavaModule,实现 getName 方法返回 "Net",并暴露一个 getResult 方法,该方法接受 URL 和回调函数参数。

NetModule.java 类:

public class NetModule extends ReactContextBaseJavaModule {
    private static final String MODULE_NAME = "Net";

    public NetModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return MODULE_NAME;
    }

    @ReactMethod
    public void getResult(String url, final Callback callback) {
        Log.e("TAG", "正在请求数据");
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String result = "这是结果";
                    Thread.sleep(1000);
                    callback.invoke(true, result);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

2. 注册模块

同样,在 AppReactPackage.javacreateNativeModules 方法中注册 NetModule(步骤同上,略)。

3. 创建 JavaScript 封装

在 JavaScript 层新建 Net.js 文件,封装原生模块调用。

Net.js 文件:

'use strict';
var { NativeModules } = require('react-native');
var RCTNet = NativeModules.Net;

var Net = {
    getResult: function (url: string, callback: Function): void {
        RCTNet.getResult(url, callback);
    },
};

module.exports = Net;

4. 在 JavaScript 中调用

修改 index.android.js 文件,引入 Net 模块并调用 getResult 方法。

index.android.js 文件(部分代码):

import React from 'react';
import { ... } from 'react-native';
var Net = require('./Net');

Net.getResult("http://baidu.com", (code, result) => {
    console.log("callback", code, result);
});

// 其他组件代码
AppRegistry.registerComponent('AwesomeProject', () => MyAwesomeApp);

运行应用后,在 Chrome 开发者工具中可以看到回调函数输出的日志,显示请求结果。通过这种方式,您可以轻松地在 React Native 中集成原生功能,实现更复杂的跨平台交互。

0 Answers