I currently have the following activity which is created when my app starts and is declared as an activity in my AndroidManifest.xml:
AndroidManifest.xml:
<activity android:name=".IncomingActivity"></activity>
IncomingActivity.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);
}
}
I now want to be able to use this functionality on demand from React Native. I have refactored it like the below so far but when this native method is called, I just get a blank white screen and I think the problem is this line: activity.setContentView(mReactRootView);
Updated class:
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);
}
}
What is the correct way to be able to call this method to toggle the functionality but with the main activity instead of starting a new one?
In order to access your native module from JavaScript you need to first import NativeModules from React Native: import { NativeModules } from 'react-native'; You can then access the CalendarModule native module off of NativeModules .
This file exists under the android folder in your react-native application directory. The path to this file is: android/app/src/main/java/com/your-app-name/MainApplication. java .
Basically, you missed 2 things - you didn't register your UnlockDevice
in a ReactPackage
, and you didn't add your ReactPackage
to the list of packages in the application.
Also, don't forget that your native method will not be executed on the UI thread with React. So, it's your responsibility to run it there. For example, by using runOnUiThread()
as below:
...
@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);
});
}
...
So, first create a ReactPackage
class to register your module.
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;
}
}
Then, add the latter to the list of packages in your Application
class.
...
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;
}
...
For a reference, I created a sample project similar to yours that works just fine. Below is relevant code.
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";
}
}
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();
}
}
}
}
import {NativeModules} from 'react-native';
var mainActivityModule = NativeModules.MainActivityModule;
mainActivityModule.unlockScreen();
As you can see, the Toast from the Activity
is shown. That's it!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With