java - 如何重构要从 React Native 调用的原生 Android Java 方法?

标签 java android react-native react-native-android

我目前有以下 Activity ,该 Activity 在我的应用启动时创建并在我的 AndroidManifest.xml 中声明为 Activity :
AndroidManifest.xml:

<activity android:name=".IncomingActivity"></activity>
传入Activity.java:
package com.xyz;

import android.os.Build;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.WindowManager;

public class IncomingActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
            setShowWhenLocked(true);
            setTurnScreenOn(true);
        }
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);

        setContentView(R.layout.activity_incoming);
    }
}
我现在希望能够从 React Native 按需使用这个功能。到目前为止,我已经像下面这样重构了它,但是当调用这个 native 方法时,我只是得到一个空白的白屏,我认为问题出在这一行:activity.setContentView(mReactRootView);更新类:
public class UnlockDevice extends ReactContextBaseJavaModule {

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

        private ReactContext mReactContext;
        private ReactRootView mReactRootView;

    public UnlockDevice(ReactApplicationContext reactContext) {
        super(reactContext);
                mReactContext = reactContext;
                mReactRootView = new ReactRootView(reactContext);
    }

    /* React Methods */
   @ReactMethod
    public void Unlock() {
                    Activity activity = mReactContext.getCurrentActivity();

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
                    activity.setShowWhenLocked(true);
                    activity.setTurnScreenOn(true);
                }
                
                activity.getWindow().addFlags(
                        WindowManager.LayoutParams.FLAG_FULLSCREEN 
                        | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                        | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 
                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                        | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);

                activity.setContentView(mReactRootView);
    }
}
能够调用此方法来切换功能但使用主要 Activity 而不是开始新 Activity 的正确方法是什么?

最佳答案

解释
基本上,你错过了两件事 - 你没有注册你的 UnlockDeviceReactPackage ,而您没有添加 ReactPackage到应用程序中的包列表。
另外,不要忘记您的 native 方法不会在 UI 线程上执行 。 react .所以,在那里运行它是你的责任。例如,使用 runOnUiThread()如下:

...
    @ReactMethod
    public void Unlock() {
        Activity activity = mReactContext.getCurrentActivity();

        activity.runOnUiThread(() -> {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
                activity.setShowWhenLocked(true);
                activity.setTurnScreenOn(true);
            }

            activity.getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_FULLSCREEN
                        | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                        | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                        | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
            activity.setContentView(mReactRootView);
        });
   }
...
所以,首先创建一个 ReactPackage类来注册你的模块。
MainReactPackage.java
public class MainReactPackage implements ReactPackage {
   @Override
   @NonNull
   public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
       return Collections.emptyList();
   }

   @Override
   @NonNull
   public List<NativeModule> createNativeModules(
           @NonNull ReactApplicationContext reactContext) {
       List<NativeModule> modules = new ArrayList<>();

       modules.add(new UnlockDevice(reactContext));

       return modules;
   }
}
然后,将后者添加到您的 Application 中的软件包列表中。类(class)。
你的应用程序.java
 ...

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

        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          packages.add(new MainReactPackage());
          return packages;
        }

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

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }
...
完整代码
作为引用,我创建了一个与您的类似的示例项目,它工作得很好。下面是相关代码。
MainActivity.java
package com.reacttest;

import android.os.Bundle;

import com.facebook.react.ReactActivity;

public class MainActivity extends ReactActivity {

    /**
     * Returns the name of the main component registered from JavaScript. This is used to schedule
     * rendering of the component.
     */
    @Override
    protected String getMainComponentName() {
        return "ReactTest";
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
    }
}
主 Activity 模块
package com.reacttest;

import android.app.Activity;
import android.os.Build;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;

import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

public class MainActivityModule extends ReactContextBaseJavaModule {

    private ReactContext mReactContext;
    private ReactRootView mReactRootView;

    public MainActivityModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mReactContext = reactContext;
        mReactRootView = new ReactRootView(reactContext);
    }

    @ReactMethod
    public void helloFromAndroid() {
        Activity activity = mReactContext.getCurrentActivity();
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
                    activity.setShowWhenLocked(true);
                    activity.setTurnScreenOn(true);
                }

                activity.getWindow().addFlags(
                        WindowManager.LayoutParams.FLAG_FULLSCREEN
                                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
                activity.setContentView(mReactRootView);
                Toast.makeText(activity, "Hello from Android", Toast.LENGTH_LONG).show();
            }
        });
    }

    @NonNull
    @Override
    public String getName() {
        return "MainActivityModule";
    }
}
MainActivityPackage.java
package com.reacttest;

import androidx.annotation.NonNull;

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 MainReactPackage implements ReactPackage {
    @Override
    @NonNull
    public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    @NonNull
    public List<NativeModule> createNativeModules(
            @NonNull ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();

        modules.add(new MainActivityModule(reactContext));

        return modules;
    }
}
MainApplication.java
package com.reacttest;

import android.app.Application;
import android.content.Context;

import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;

import java.lang.reflect.InvocationTargetException;
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() {
                    @SuppressWarnings("UnnecessaryLocalVariable")
                    List<ReactPackage> packages = new PackageList(this).getPackages();
                    packages.add(new MainReactPackage());
                    return packages;
                }

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

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

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

    /**
     * Loads Flipper in React Native templates. Call this in the onCreate method with something like
     * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
     *
     * @param context
     * @param reactInstanceManager
     */
    private static void initializeFlipper(
            Context context, ReactInstanceManager reactInstanceManager) {
        if (BuildConfig.DEBUG) {
            try {
        /*
         We use reflection here to pick up the class that initializes Flipper,
        since Flipper library is not available in release mode
        */
                Class<?> aClass = Class.forName("com.reacttest.ReactNativeFlipper");
                aClass
                        .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
                        .invoke(null, context, reactInstanceManager);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}
应用程序.js
import {NativeModules} from 'react-native';

var mainActivityModule = NativeModules.MainActivityModule;
mainActivityModule.unlockScreen();
结果
enter image description here
如您所见,来自 Activity 的 Toast显示。而已!

关于java - 如何重构要从 React Native 调用的原生 Android Java 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66662941/

相关文章:

java - 如何使用其他编程语言(C、C++等)的程序检查Java是否安装以及安装位置

android - 嵌套 ScrollView + TextView + RecyclerView

android - 仅在某些设备上发生异常崩溃 - 异步调用 kotlin 协程

android - event.getSource() 在 android 中返回空辅助功能

android - 如何使用 AWS Pinpoint 通过 postman 发送推送通知

react-native - React Native 错误 - 不变违规 : ART has been removed from React Native

java - 确定 okhttp 异步请求的优先级

java - 如何使用spring注解将一个POJO对象注入(inject)到另一个POJO?

java - 验证变量在 Java 范围内

react-native - React Native中FlatList的性能问题