React Native 實現iOS和Android自定義消息推送通知聲音

因為公司app的需求,需要加個自定義消息推送通知聲音,因為不懂安卓的原生,所以之前被卡了很久,查了很多資料,終于搞定了,下面分享iOS和Android環境下的如何根據后臺傳過來的參數來指定播放app端的消息通知聲音。
開始之前,需要先安裝三方庫jpush-react-native,這里我就不詳細說了,按照文檔做就可以了。

iOS端

由于自定義通知聲音還是由 iOS 系統來播放的,所以對音頻數據格式有限制,可以是如下四種之一:

Linear PCM
MA4 (IMA/ADPCM)
μLaw
aLaw
對應音頻文件格式是 aiff,wav,caf 文件,文件也必須放到 app 的 mainBundle 目錄中。
自定義通知聲音的播放時間必須在 30s 內,如果超過這個限制,則將用系統默認通知聲音替代。
可以使用 afconvert 工具來處理音頻文件格式,在終端中敲入如下命令就可以將一個 mp3 文件轉換成 caf 文件:

$ afconvert test.mp3 test.caf -d ima4 -f caff -v

轉換完成后就可以將 test.caf 這個文件拖入 Xcode 工程中,編譯運行項目在真機上。


image.png

發送推送通知時,只需后臺配置 sound 字段的值為導入到工程中的音頻文件名,這里即就是 test.caf。

如果要用系統自帶的聲音,必須傳'default',不然app端就沒有聲音了。

iOS的就搞定了,是不是很簡單。這里其實用不著jpush-react-native庫,只要還是為了下面的安卓使用的。

Android端

安卓端的就稍微有點復雜了,因為不懂原生安卓的原因,花了我不少時間。
首先將聲音文件放在raw目錄下,沒有此目錄自己創建一個

注意,此時就用到了jpush-react-native庫了,文件要放在庫里,還有一點就是安卓自定義聲音只支持發送自定義消息,發送普通通知是不可以的。

WechatIMG36.jpeg

然后到jpush-react-native里的android/src/main/java/cn/jpush/reactnativejpush下找到JPushModule.java修改里面的代碼
找到接收自定義消息函數JPushReceiver,將里面的接收自定義函數代碼

public static class JPushReceiver extends BroadcastReceiver {

        public JPushReceiver() {
        }

        @Override
        public void onReceive(Context context, Intent data) {
            mCachedBundle = data.getExtras();
            if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(data.getAction())) {
                try {
                    String message = data.getStringExtra(JPushInterface.EXTRA_MESSAGE);
                    Logger.i(TAG, "收到自定義消息: " + message);
                    if (mRAC != null) {
                        WritableMap map = Arguments.createMap();
                        map.putString("message", message);
                        map.putString("extras", data.getExtras().getString(JPushInterface.EXTRA_EXTRA));
                        mRAC.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                                .emit(RECEIVE_CUSTOM_MESSAGE, map);
                    } else {
                        mEvent = RECEIVE_CUSTOM_MESSAGE;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(data.getAction())) {

改成

public static class JPushReceiver extends BroadcastReceiver {

        public JPushReceiver() {
        }

        @Override
        public void onReceive(Context context, Intent data) {
            mCachedBundle = data.getExtras();
            if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(data.getAction())) {
               processCustomMessage(context, mCachedBundle);
                try {
                    String message = data.getStringExtra(JPushInterface.EXTRA_MESSAGE);
                    Logger.i(TAG, "收到自定義消息: " + message);
                    if (mRAC != null) {
                        WritableMap map = Arguments.createMap();
                        map.putString("message", message);
                        map.putString("extras", data.getExtras().getString(JPushInterface.EXTRA_EXTRA));
                        mRAC.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                                .emit(RECEIVE_CUSTOM_MESSAGE, map);
                    } else {
                        mEvent = RECEIVE_CUSTOM_MESSAGE;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(data.getAction())) {

其實就是多加了一行processCustomMessage(context, mCachedBundle);
然后在寫processCustomMessage函數

private void processCustomMessage(Context context, Bundle bundle) {

            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

            NotificationCompat.Builder notification = new NotificationCompat.Builder(context);

             String message = bundle.getString(JPushInterface.EXTRA_MESSAGE);
            String title = bundle.getString(JPushInterface.EXTRA_TITLE);
            notification.setAutoCancel(true)
                    .setContentText(message)
                    .setContentTitle(title)
                    .setSmallIcon(R.mipmap.ic_launcher);
            String extras = bundle.getString(JPushInterface.EXTRA_EXTRA);
            if (!TextUtils.isEmpty(extras)) {
                try {
                    JSONObject extraJson = new JSONObject(extras);
                    if (null != extraJson && extraJson.length() > 0) {

                        String sound = extraJson.getString("sound");
                        if("invite_price.mp3".equals(sound)){
                            notification.setSound(Uri.parse("android.resource://" + context.getPackageName() + "/" +R.raw.invite_price));
                        }else if("test.mp3".equals(sound)){
                            notification.setSound(Uri.parse("android.resource://" + context.getPackageName() + "/" +R.raw.test));
                        }else{
                            notification.setDefaults(1);
                        }

                    }
                } catch (JSONException e) {

                }

            }
            int timecurrentTimeMillis =(int)System.currentTimeMillis()/1000 ;
            Intent intent = new Intent();
            intent.setClass(context, JPushReceiver.class);
            intent.setAction(JPushInterface.ACTION_NOTIFICATION_OPENED);
            intent.putExtras(bundle);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, timecurrentTimeMillis, intent, PendingIntent.FLAG_ONE_SHOT);
            notification.setContentIntent(pendingIntent);
            notificationManager.notify(timecurrentTimeMillis, notification.build());
}

注意后臺傳給你的參數是在extras里的,里面的sound字段就對應你本地的文件名,比如我這里的invite_price.mp3文件,sound即為'invite_price.mp3',如果想要使用系統默認的,那就傳個不存在的文件名,統一最好就用'default'吧。timecurrentTimeMillis是通知唯一標識符,如果不設置的話,相當于id一直沒變,這樣會導致新的通知會覆蓋舊的通知,通知列表永遠只有1個。最后如果提示有紅色的未定義的函數名,引入一下就好了。

      int timecurrentTimeMillis =(int)System.currentTimeMillis()/1000 ;
      Intent intent = new Intent();
      intent.setClass(context, JPushReceiver.class);
      intent.setAction(JPushInterface.ACTION_NOTIFICATION_OPENED);
      intent.putExtras(bundle);
      PendingIntent pendingIntent = PendingIntent.getBroadcast(context, timecurrentTimeMillis, intent, PendingIntent.FLAG_ONE_SHOT);
      notification.setContentIntent(pendingIntent);
      notificationManager.notify(timecurrentTimeMillis, notification.build());

這塊代碼的意思是點擊通知并且發送到廣播里,這樣在js里就可以通過JPushModule.addReceiveOpenNotificationListener()來監聽到點擊通知的事件。

至此,iOS和Android的自定義通知聲音就OK啦。如果有哪里寫的不好的,還望指正啊,不明白的也可以在下面留言,我看到就會回復的。或者加jpush-react-native官方群553406342

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容