发布时间:2024-07-09 14:01
前段时间,公司需要用React Native做一套电视机顶盒上的视频播放系统,而其中有一项功能是需要读取到机顶盒的卡号,这个卡号提前被生产商写入了系统属性,叫“persist.sys.mmcp.smarcardid”,通过在命令行运行adb shell后,再运行getprop命令可以查出来,如下图:
但React Native本身并不提供直接读取系统属性的功能,这时候就需要手动开发一个原生插件来完成这项功能,具体步骤如下。
在android\app\src\main\java\com\videoplayer下创建一个java类SystemProperty.java
源码如下:
package com.videoplayer;
import android.widget.Toast;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import androidx.annotation.NonNull;
public class SystemProperty extends ReactContextBaseJavaModule {
private static ReactApplicationContext reactContext;
private static Method sysPropGet;
private static Method sysPropSet;
static {
try {
Class> S = Class.forName("android.os.SystemProperties");
Method M[] = S.getMethods();
for (Method m : M) {
String n = m.getName();
if (n.equals("get")) {
sysPropGet = m;
} else if (n.equals("set")) {
sysPropSet = m;
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public SystemProperty(ReactApplicationContext context) {
super(context);
reactContext = context;
}
@NonNull
@Override
public String getName() {
return "SystemProperty";
}
@ReactMethod
public void getSystemProperty(String name,Promise promise) {
try {
String value=(String) sysPropGet.invoke(null, name,"");
promise.resolve(value);
} catch (Exception e) {
Toast.makeText(getReactApplicationContext(), "获取卡号出错", Toast.LENGTH_LONG).show();
promise.reject("获取卡号出错", e);
e.printStackTrace();
}
}
}
该类继承了ReactContextBaseJavaModule,这是开发React Native插件必须要继承的类,并在getName方法中返回SystemProperty,当然也可以返回其他名字,这个名字是在前端JavaScript中要用到的。其中getSystemProperty方法的第一个参数为要获取的系统属性名,第二个参数为Promise类型,在JavaScript端可以使用awiat或then的方式获取数据。
Java 方法需要使用注解@ReactMethod。方法的返回类型必须为void。React Native 的跨语言访问是异步进行的,所以想要给 JavaScript 返回一个值的唯一办法是使用回调函数或者发送事件。
在 Java 这边要做的最后一件事就是注册这个模块。我们需要在应用的 Package 类的createNativeModules方法中添加这个模块。如果模块没有被注册,它也无法在 JavaScript 中被访问到。在android\app\src\main\java\com\videoplayer下创建一个java类SystemPropertyPackage.java。这个 package 需要在MainApplication.java
文件的getPackages
方法中提供。这个文件位于你的 react-native 应用文件夹的 android 目录中。
源码如下:
package com.videoplayer;
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 androidx.annotation.NonNull;
public class SystemPropertyPackage implements ReactPackage {
@NonNull
@Override
public List createNativeModules(@NonNull ReactApplicationContext reactContext) {
List modules = new ArrayList<>();
modules.add(new SystemProperty(reactContext));
return modules;
}
@NonNull
@Override
public List createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
在MainApplication.java中添加如下行,注册SystemProperty插件
import {
NativeModules
} from 'react-native';
let value=await NativeModules.SystemProperty.getSystemProperty("persist.sys.mmcp.smarcardid");