Implementing Restart App Functionality in React Native with Native Modules (Java, Objective-C) new Architecture
Android Native module:
Exposing Java Methods: to make specific Java methods callable from JavaScript, you use the
@ReactMethod
annotation. This annotation tells React Native to treat the annotated method as a callable function from the JavaScript side.Methods Invoked from JavaScript: functions marked with
@ReactMethod
can be called directly from JavaScript using the module instance on the JavaScript side.
- Create a ‘restart’ module folder at: android/src/main/java/com/your-app/app.
- RestartModule.java
package com."your-app".app.restart;
import android.app.Activity;
import android.os.Handler;
import android.os.Looper;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
public class RestartModule extends ReactContextBaseJavaModule {
private static String restartReason = null;
private LifecycleEventListener mLifecycleEventListener = null;
public RestartModule(ReactApplicationContext reactContext) {
super(reactContext);
}
private void loadBundleLegacy() {
final Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
return;
}
currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
currentActivity.recreate();
}
});
}
private void loadBundle() {
clearLifecycleEventListener();
try {
final ReactInstanceManager instanceManager = resolveInstanceManager();
if (instanceManager == null) {
return;
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
try {
instanceManager.recreateReactContextInBackground();
} catch (Throwable t) {
loadBundleLegacy();
}
}
});
} catch (Throwable t) {
loadBundleLegacy();
}
}
private static ReactInstanceHolder mReactInstanceHolder;
static ReactInstanceManager getReactInstanceManager() {
if (mReactInstanceHolder == null) {
return null;
}
return mReactInstanceHolder.getReactInstanceManager();
}
private ReactInstanceManager resolveInstanceManager() throws NoSuchFieldException, IllegalAccessException {
ReactInstanceManager instanceManager = getReactInstanceManager();
if (instanceManager != null) {
return instanceManager;
}
final Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
return null;
}
ReactApplication reactApplication = (ReactApplication) currentActivity.getApplication();
instanceManager = reactApplication.getReactNativeHost().getReactInstanceManager();
return instanceManager;
}
private void clearLifecycleEventListener() {
if (mLifecycleEventListener != null) {
getReactApplicationContext().removeLifecycleEventListener(mLifecycleEventListener);
mLifecycleEventListener = null;
}
}
@ReactMethod
public void restart(String reason) {
restartReason = reason;
loadBundle();
}
@ReactMethod
public void getReason(Promise promise) {
try {
promise.resolve(restartReason);
} catch(Exception e) {
promise.reject("Create Event Error", e);
}
}
@Override
public String getName() {
return "RNRestart";
}
}
3. ReactInstanceHolder.java
package com."your-app".app.restart;
import com.facebook.react.ReactInstanceManager;
public interface ReactInstanceHolder {
ReactInstanceManager getReactInstanceManager();
}
4. RestartPackage.java
package com."your-app".app.restart;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
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 RestartPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new RestartModule(reactContext));
return modules;
}
}
5. MainApplication.java
import com."your-app".app.restart.RestartPackage;
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new RestartPackage()); // <-- add here
return packages;
}
iOS Native module
RCT_EXPORT_MODULE
is used to expose a native module to the JavaScript environment. Native modules in React Native are used to provide a bridge between JavaScript and native code.
RCT_EXPORT_METHOD
is used to expose specific methods of a native module, making them accessible from JavaScript.
- Create a custom native module file in Xcode: Restart.h (Header File) and Restart.m (Objective-C File).
2. Restart.h
#import <React/RCTBridgeModule.h>
#import <React/RCTRootView.h>
#import <React/RCTReloadCommand.h>
@interface Restart : NSObject <RCTBridgeModule>
@end
3. Restart.m
#import "Restart.h"
@implementation Restart
RCT_EXPORT_MODULE(RNRestart)
NSString *restartReason = nil;
- (void)loadBundle
{
RCTTriggerReloadCommandListeners(@"react-native-restart: Restart");
}
RCT_EXPORT_METHOD(restart: (NSString *)reason) {
restartReason = reason;
if ([NSThread isMainThread]) {
[self loadBundle];
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
[self loadBundle];
});
}
return;
}
@end
Now, use it in JS
// RNRestartModule.ts
import {NativeModules} from 'react-native';
interface RNRestartInterface {
restart(reason: string): void;
}
export const RNRestart = NativeModules.RNRestart as RNRestartInterface;
In component
import { RNRestart } from "@utils"
<Button onPress={() => RNRestart.restart("")} />