In order to improve the rate of push delivery, the product proposed a requirement: when APP push is closed, a small TIP will be displayed. Click TIP to jump to the APP message setting interface.


Our APP is developed based on React Native. These functions are not officially provided by Facebook, so we need to develop corresponding Native modules.

Since developing native modules is a bit more in-depth, I’m writing this article with the assumption that the reader already has some Objective-C and Java development skills.


The basics of developing a native module can be seen directly in the official documentation, which is very detailed and I won’t repeat it here.

React Native develops Android Native modules

React Native develops iOS Native modules


Let’s start analyzing the implementation.


Step 1: Get APP push status

My main reference here is the aurora push. Because the company has a unified push SDK (mainly integrating the push services of many push service companies and mobile phone manufacturers in the market), some convenient functions of aurora push cannot be used for the time being, so we have to refer to and implement them by ourselves.


  1. Compatible with multiple system versions (partly thanks to aurora Push developers);
  2. In order toPromiseThe form of encapsulation (aurora push is based oncallback)


GetSystemNoticeStatus () returns true if the APP push is on, false if it is not.


The iOS code is as follows:

Reference link: github.com/jpush/jpush…

RCT_EXPORT_METHOD( getSystemNoticeStatus: (RCTPromiseResolveBlock) resolve rejecter: (RCTPromiseRejectBlock) reject ) { dispatch_async( dispatch_get_main_queue(), ^{ float systemVersion = [[UIDevice currentDevice].systemVersion floatValue]; If (systemVersion > = 8.0) {UIUserNotificationSettings * Settings = [[UIApplication sharedApplication] currentUserNotificationSettings]; UIUserNotificationType type = settings.types; if ( type == UIUserNotificationTypeNone ) { return(resolve (@NO) ); }else { return(resolve (@YES) ); }} else if (systemVersion > = 10.0) {[[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler: ^ (UNNotificationSettings * _Nonnull settings) { switch ( settings.authorizationStatus ) { case UNAuthorizationStatusDenied: case UNAuthorizationStatusNotDetermined: return(resolve (@NO) ); break; case UNAuthorizationStatusAuthorized: return(resolve (@YES) ); break; } }]; }}); }Copy the code

The Android code is as follows:

Reference links:

Github.com/jpush/jpush…

/** * Get APP system notification status ** */
@ReactMethod
public void getSystemNoticeStatus(Promise promise) {
    promise.resolve(hasPermission("OP_POST_NOTIFICATION"));
}

private boolean hasPermission(String appOpsServiceId) {

    Context context = getReactApplicationContext();
    if (Build.VERSION.SDK_INT >= 24) {
        NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(
                Context.NOTIFICATION_SERVICE);
        return mNotificationManager.areNotificationsEnabled();
    }else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
        AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        ApplicationInfo appInfo = context.getApplicationInfo();

        String pkg = context.getPackageName();
        int uid = appInfo.uid;
        Class appOpsClazz;

        try {
            appOpsClazz = Class.forName(AppOpsManager.class.getName());
            Method checkOpNoThrowMethod = appOpsClazz.getMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE,
                    String.class);
            Field opValue = appOpsClazz.getDeclaredField(appOpsServiceId);
            int value = opValue.getInt(Integer.class);
            Object result = checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg);
            return Integer.parseInt(result.toString()) == AppOpsManager.MODE_ALLOWED;
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch(ClassNotFoundException e) { e.printStackTrace(); }}return false;
}
Copy the code


And then we can reference it directly on the JavaScript side

import {
    Platform,
    NativeModules,
} from 'react-native';

function getSystemNoticeStatus() {
    NativeModules.appName.getSystemNoticeStatus().then((isOpen) = > {
        console.log('getSystemNotice', isOpen) // 
    }).catch((e) = > {
        console.log('getSystemNoticeStatus error', e)
    });
}
Copy the code




Step 2: Jump to the APP Settings interface

Jumping to APP setting interface should also consider the compatibility of different system versions. For example, iOS11+ now only allows to jump to the system Settings home page/the application Settings interface, Android also consider different manufacturers of APP Settings page magic change, is a headache.

First of all, iOS adaptation, we directly jump to the app Settings home page, as shown below:

Linking. OpenURL (‘app-settings:’);


Android is going to have some more code, see the notes for specific adaptation:

/** ** Jump to system notification Settings * this.appContext indicates the context of the file/application ** /
@ReactMethod
public void openSystemNoticeView(a){
    try {
        // Go to the notification setting interface
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);

        // This solution applies to API 26, i.e. 8.0 and above
        intent.putExtra(EXTRA_APP_PACKAGE, this.appContext.getPackageName());
        intent.putExtra(EXTRA_CHANNEL_ID, this.appContext.getApplicationInfo().uid);

        This scheme applies to API21 -- 25, that is, versions 5.0 -- 7.1 can be used
        intent.putExtra("app_package".this.appContext.getPackageName());
        intent.putExtra("app_uid".this.appContext.getApplicationInfo().uid);

        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        this.appContext.startActivity(intent);
    } catch (Exception e) {
        e.printStackTrace();
        // If there is an exception, go to the application setting interface: hammer
        Intent intent = new Intent();

        // Jump directly to the Settings screen of the current application.
        //https://blog.csdn.net/ysy950803/article/details/71910806
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package".this.appContext.getPackageName(), null);
        intent.setData(uri);

        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        this.appContext.startActivity(intent); }}Copy the code


Then we do some compatibility on the JavaScript side:

import {
    Linking,
    Platform,
} from 'react-native';

/** * Jump to APP message setting page ** /
export function openSystemNoticeSetting() {
    if (Platform.OS === "android") {
        NativeModules.appName.openSystemNoticeView();
    } else {
        Linking.openURL('app-settings:')
            .catch(err= > console.log('openSystemSetting error', err)); }}Copy the code





The above are the two difficulties encountered in the development, if you think this article is useful to you, you can click a “like” to express my encouragement, thank you.


Finally, I would like to recommend my personal official account “Lu Egg Lab”. I usually share some front-end technology and data analysis content. If you are interested, you can pay attention to the following: