因為公司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 工程中,編譯運行項目在真機上。
發送推送通知時,只需后臺配置 sound 字段的值為導入到工程中的音頻文件名,這里即就是 test.caf。
如果要用系統自帶的聲音,必須傳'default',不然app端就沒有聲音了。
iOS的就搞定了,是不是很簡單。這里其實用不著jpush-react-native庫,只要還是為了下面的安卓使用的。
Android端
安卓端的就稍微有點復雜了,因為不懂原生安卓的原因,花了我不少時間。
首先將聲音文件放在raw目錄下,沒有此目錄自己創建一個
注意,此時就用到了jpush-react-native庫了,文件要放在庫里,還有一點就是安卓自定義聲音只支持發送自定義消息,發送普通通知是不可以的。
然后到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