diff --git a/Libraries/Linking/Linking.js b/Libraries/Linking/Linking.js index a1d0b2ae38f..6dfd3c7cccc 100644 --- a/Libraries/Linking/Linking.js +++ b/Libraries/Linking/Linking.js @@ -71,6 +71,15 @@ class Linking extends NativeEventEmitter { return LinkingManager.canOpenURL(url); } + /** + * Open app settings. + * + * See https://facebook.github.io/react-native/docs/linking.html#opensettings + */ + openSettings(): Promise { + return LinkingManager.openSettings(); + } + /** * If the app launch was triggered by an app link, * it will give the link url, otherwise it will give `null` diff --git a/Libraries/LinkingIOS/RCTLinkingManager.m b/Libraries/LinkingIOS/RCTLinkingManager.m index 392e1620616..f86266a7e43 100644 --- a/Libraries/LinkingIOS/RCTLinkingManager.m +++ b/Libraries/LinkingIOS/RCTLinkingManager.m @@ -153,4 +153,26 @@ RCT_EXPORT_METHOD(getInitialURL:(RCTPromiseResolveBlock)resolve resolve(RCTNullIfNil(initialURL.absoluteString)); } +RCT_EXPORT_METHOD(openSettings:(RCTPromiseResolveBlock)resolve + reject:(__unused RCTPromiseRejectBlock)reject) +{ + NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; + if (@available(iOS 10.0, *)) { + [RCTSharedApplication() openURL:url options:@{} completionHandler:^(BOOL success) { + if (success) { + resolve(nil); + } else { + reject(RCTErrorUnspecified, @"Unable to open app settings", nil); + } + }]; + } else { + BOOL opened = [RCTSharedApplication() openURL:url]; + if (opened) { + resolve(nil); + } else { + reject(RCTErrorUnspecified, @"Unable to open app settings", nil); + } + } +} + @end diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java index ed0b54a4070..50c6d405809 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java @@ -12,6 +12,7 @@ import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; +import android.provider.Settings; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.Promise; @@ -140,9 +141,36 @@ public class IntentModule extends ReactContextBaseJavaModule { } } + /** + * Starts an external activity to open app's settings into Android Settings + * + * @param promise a promise which is resolved when the Settings is opened + */ + @ReactMethod + public void openSettings(Promise promise) { + try { + Intent intent = new Intent(); + Activity currentActivity = getCurrentActivity(); + String selfPackageName = getReactApplicationContext().getPackageName(); + + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(Uri.parse("package:" + selfPackageName)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + currentActivity.startActivity(intent); + + promise.resolve(true); + } catch (Exception e) { + promise.reject(new JSApplicationIllegalArgumentException( + "Could not open the Settings: " + e.getMessage())); + } + } + /** * Allows to send intents on Android - * + * * For example, you can open the Notification Category screen for a specific application * passing action = 'android.settings.CHANNEL_NOTIFICATION_SETTINGS' * and extras = [ diff --git a/jest/setup.js b/jest/setup.js index 67b41d7bbc9..17aa9ccc5f9 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -165,6 +165,7 @@ const mockNativeModules = { Linking: { openURL: jest.fn(), canOpenURL: jest.fn(() => Promise.resolve(true)), + openSettings: jest.fn(), addEventListener: jest.fn(), getInitialURL: jest.fn(() => Promise.resolve()), removeEventListener: jest.fn(),