React Native集成C库遇Buck报错,求RN与C双向传参实现方案
我懂你现在的难处——没接触过Android开发,还要对接C语言的游戏引擎,选了React Native本来想靠NodeJS基础过渡,结果Buck工具先给你泼了冷水。先帮你理清Buck的问题,再给你一个更适合入门的方案:用React Native原生模块+Android NDK实现双向传参,上手更快,资料也更全。
先解决你的Buck错误
你执行的命令有几个明显的语法问题,这也是报错的原因:
mkdir buck-project cd buck-project是两个独立命令,需要分开执行:mkdir buck-project cd buck-projectbuck project buck-project --ide intellij语法错误,正确写法是buck project --ide intellij(不需要重复项目名)buck installbuck-project应该是buck install //your:target-name,而且你还没定义Buck的构建目标,自然会报“引用不存在的目录”
不过说实话,Buck的学习曲线对新手来说太陡了,尤其是你没有Android开发背景,不如用React Native官方支持的原生模块+NDK方案,下面是完整的入门示例:
入门示例:React Native与C代码双向传参
第一步:初始化React Native项目
先创建一个新的RN项目(已有项目可跳过):
npx react-native init RNCInteropDemo cd RNCInteropDemo
第二步:创建Android原生模块(RN与C的中间层)
在android/app/src/main/java/com/rncinteropdemo/目录下创建以下文件:
1. CInteropModule.java(核心交互类)
package com.rncinteropdemo; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.Callback; public class CInteropModule extends ReactContextBaseJavaModule { static { // 加载我们后续编译的C库 System.loadLibrary("native-lib"); } public CInteropModule(ReactApplicationContext reactContext) { super(reactContext); } @Override public String getName() { // RN中调用该模块的名称 return "CInterop"; } // RN调用C函数:传递字符串参数,获取返回值 @ReactMethod public void callCFunction(String input, Callback callback) { String result = nativeProcessString(input); callback.invoke(null, result); } // C主动调用RN的方法:触发事件传递参数 @ReactMethod public void triggerCToRNEvent(String message) { callRNFunction(getReactApplicationContext().getJNIEnv(), getReactApplicationContext(), message); } // 声明C函数(具体实现放在C文件中) public native String nativeProcessString(String input); public native void callRNFunction(JNIEnv env, jobject reactContext, jstring message); }
2. CInteropPackage.java(注册模块)
package com.rncinteropdemo; 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; public class CInteropPackage implements ReactPackage { @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); modules.add(new CInteropModule(reactContext)); return modules; } @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); } }
3. 注册Package到MainApplication.java
找到getPackages()方法,添加我们的包:
@Override protected List<ReactPackage> getPackages() { List<ReactPackage> packages = new PackageList(this).getPackages(); // 添加这一行 packages.add(new CInteropPackage()); return packages; }
第三步:编写C代码实现业务逻辑
在android/app/src/main/目录下创建jni文件夹,然后创建以下文件:
1. native-lib.c(C代码核心)
#include <jni.h> #include <string.h> #include <android/log.h> #define LOG_TAG "CInterop" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) // RN调用C:处理字符串并返回 JNIEXPORT jstring JNICALL Java_com_rncinteropdemo_CInteropModule_nativeProcessString(JNIEnv *env, jobject thiz, jstring input) { const char *inputStr = (*env)->GetStringUTFChars(env, input, NULL); if (inputStr == NULL) { return NULL; } // 示例:给输入字符串添加前缀 char result[100]; snprintf(result, sizeof(result), "C代码处理结果:%s", inputStr); LOGD("收到RN传递的参数:%s", inputStr); // 释放JNI字符串资源 (*env)->ReleaseStringUTFChars(env, input, inputStr); return (*env)->NewStringUTF(env, result); } // C主动调用RN:发送事件传递参数 JNIEXPORT void JNICALL Java_com_rncinteropdemo_CInteropModule_callRNFunction(JNIEnv *env, jobject thiz, jobject reactContext, jstring message) { // 获取RN的事件发射器类 jclass reactContextClass = (*env)->FindClass(env, "com/facebook/react/bridge/ReactApplicationContext"); jmethodID getJSModuleMethod = (*env)->GetMethodID(env, reactContextClass, "getJSModule", "(Ljava/lang/Class;)Ljava/lang/Object;"); jclass eventEmitterClass = (*env)->FindClass(env, "com/facebook/react/modules/core/DeviceEventManagerModule$RCTDeviceEventEmitter"); jobject eventEmitter = (*env)->CallObjectMethod(env, reactContext, getJSModuleMethod, eventEmitterClass); // 调用RN的emit方法发送事件 jmethodID emitMethod = (*env)->GetMethodID(env, eventEmitterClass, "emit", "(Ljava/lang/String;Ljava/lang/Object;)V"); (*env)->CallVoidMethod(env, eventEmitter, emitMethod, (*env)->NewStringUTF(env, "CToRNEvent"), message); // 释放JNI资源 (*env)->DeleteLocalRef(env, reactContextClass); (*env)->DeleteLocalRef(env, eventEmitterClass); (*env)->DeleteLocalRef(env, eventEmitter); }
2. Android.mk(NDK编译配置)
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := native-lib LOCAL_SRC_FILES := native-lib.c LOCAL_LDLIBS := -llog # 引入日志库,方便调试 include $(BUILD_SHARED_LIBRARY)
3. Application.mk(NDK平台配置)
APP_ABI := all # 编译所有架构的库 APP_PLATFORM := android-23 # 最低支持Android 6.0
第四步:配置NDK编译环境
打开android/build.gradle(项目根目录下的那个),在buildscript的ext中添加NDK版本(用你本地安装的版本即可):
buildscript { ext { buildToolsVersion = "33.0.0" minSdkVersion = 23 compileSdkVersion = 33 targetSdkVersion = 33 ndkVersion = "25.1.8937393" } // 其他代码... }
然后打开android/app/build.gradle,在android块中添加NDK编译配置:
android { // 其他代码... defaultConfig { // 其他代码... ndk { abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" } externalNativeBuild { ndkBuild { path "src/main/jni/Android.mk" } } } // 添加externalNativeBuild块 externalNativeBuild { ndkBuild { path "src/main/jni/Android.mk" } } }
第五步:在RN中测试双向传参
修改App.js,实现调用C函数和监听C发送的事件:
import React, { useEffect, useState } from 'react'; import { View, Text, Button, NativeModules, DeviceEventEmitter } from 'react-native'; const { CInterop } = NativeModules; const App = () => { const [cResult, setCResult] = useState(''); const [cMessage, setCMessage] = useState(''); // 调用C函数,传递参数并获取返回值 const handleCallC = () => { CInterop.callCFunction('Hello from RN!', (error, res) => { if (error) console.error(error); else setCResult(res); }); }; // 触发C主动发送消息到RN const handleTriggerCEvent = () => { CInterop.triggerCToRNEvent('Hello from C!'); }; // 监听C发送的事件 useEffect(() => { const listener = DeviceEventEmitter.addListener('CToRNEvent', (msg) => { setCMessage(msg); }); return () => listener.remove(); }, []); return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 }}> <Button title="调用C函数" onPress={handleCallC} /> {cResult && <Text style={{ marginTop: 20 }}>{cResult}</Text>} <Button title="触发C主动发消息" onPress={handleTriggerCEvent} style={{ marginTop: 30 }} /> {cMessage && <Text style={{ marginTop: 20, color: 'blue' }}>C主动推送:{cMessage}</Text>} </View> ); }; export default App;
第六步:运行项目
连接Android设备或启动模拟器,执行命令:
npx react-native run-android
现在你就能看到:点击第一个按钮,RN调用C函数并获取返回值;点击第二个按钮,C主动向RN发送消息,完美实现双向传参。
内容的提问来源于stack exchange,提问作者Larry
相关产品推荐
相关产品推荐

