前段时间,公司需要用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<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
- List<NativeModule> modules = new ArrayList<>();
-
- modules.add(new SystemProperty(reactContext));
-
- return modules;
- }
-
- @NonNull
- @Override
- public List<ViewManager> 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");