如何重构要从ReactNative调用的原生AndroidJava方法?
我目前有以下活动,它是在我的应用程序启动时创建的,并在我的 AndroidManifest.xml 中声明为活动:
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 按需使用此功能。到目前为止,我已经像下面这样重构了它,但是当调用这个本机方法时,我只是得到一个空白的白屏,我认为问题出在这一行: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);
}
}
能够调用此方法来切换功能但使用主要活动而不是启动新活动的正确方法是什么?
回答
解释
基本上,你错过了两件事——你没有UnlockDevice在 a 中注册你的ReactPackage,并且你没有将你ReactPackage的添加到应用程序的包列表中。
另外,不要忘记您的本机方法不会在带有React的 UI 线程上执行。因此,您有责任在那里运行它。例如,通过使用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类中的包列表中。
你的应用程序
...
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;
}
...
完整代码
作为参考,我创建了一个与您类似的示例项目,效果很好。下面是相关代码。
主活动.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);
}
}
主活动模块
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";
}
}
主活动包.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;
}
}
主应用程序
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();
结果
如您所见,显示了来自 的 Toast Activity。就是这样!