關於Android 7.0系統通知聲音不能播放
阿新 • • 發佈:2019-01-04
由於沉迷於擼(nong)碼(yao),很久沒有更新過部落格了,甚是慚愧.公司的專案比較高大上,主要面對老外開發,所以要適配各種版本的Android機,專案裡有個鬧鐘提醒患者吃藥的功能,但是這個功能獲取系統通知鈴聲在Android 6.0以下好好的,換了個7.0的手機卻不能播放出聲音了.Android的鍋,我們不背,我們不背…但是能解決的還是解決下吧.
問題現象及問題定位
NotificationCompat.Builder.setSound(URI)的時候,發現沒有發出任何聲音,但是卻顯示出了一個錯誤.
問題分析
將系統鈴聲設定為系統通知鈴聲需要兩個操作
通過
RingtoneManager.ACTION_RINGTONE_PICKER,
獲取”/system/media/audio/notifications”路徑下的音樂的URI呼叫RingtoneManager.setActualDefaultRingtoneUri(),傳入相應的uri和需要設定的鈴聲型別即可。
如果你使用的是file: Uri,在targetSdkVersion>=24(Android 7.0以上)的時候是不適用的.因為Android 7.0的Uri會檢查播放的聲音是否是file:Uri禁用值
問題的解決方法
只需要在呼叫聲音的前面加一句黑程式碼 就可以完美解決
grantUriPermission("com.android.systemui", soundUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
這裡的soundUri就是你調取系統聲音的Uri
貼碼
說那麼多沒用的,不如擼一把程式碼.為了方便大家直接使用做了一個簡單的demo,方便大家參考.
也可以從github上直接下載下來,RingStom
- 佈局activity_main.xml檔案
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:id="@+id/buttonRingtone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="設定來電鈴聲"
/>
<Button
android:id="@+id/buttonAlarm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="設定鬧鐘鈴聲"
/>
<Button
android:id="@+id/buttonNotification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="設定通知鈴聲"
/>
</LinearLayout>
- 相關的java程式碼
public class MainActivity extends AppCompatActivity {
/* 3個按鈕 */
private Button mButtonRingtone;
private Button mButtonAlarm;
private Button mButtonNotification;
/* 自定義的型別 */
public static final int CODE_RINGSTONE = 0;
public static final int CODE_ALARM = 1;
public static final int CODE_NOTIFICATION = 2;
/**
* 來電鈴聲資料夾
* /system/media/audio/ringtones 系統來電鈴聲
* /sdcard/music/ringtones 使用者來電鈴聲
*/
private String strRingtoneFolder = "/system/media/audio/ringtones";
// private String strRingtoneFolder = "/sdcard/music/ringtones";
/**
* 鬧鐘鈴聲資料夾
* /system/media/audio/alarms 系統鬧鐘鈴聲
* /sdcard/music/alarms 使用者鬧鐘鈴聲
*/
private String strAlarmFolder = "/system/media/audio/alarms";
// private String strAlarmFolder = "/sdcard/music/alarms ";
/**
* 鬧鐘鈴聲資料夾
* /system/media/audio/notifications 系統通知鈴聲
* /sdcard/music/notifications 使用者通知鈴聲
*/
private String strNotificationFolder = "/system/media/audio/notifications";
// private String strNotificationFolder = "/sdcard/music/notifications";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonRingtone = (Button) findViewById(R.id.buttonRingtone);
mButtonAlarm = (Button) findViewById(R.id.buttonAlarm);
mButtonNotification = (Button) findViewById(R.id.buttonNotification);
mButtonRingtone.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (hasFolder(strRingtoneFolder)) {
// 開啟系統鈴聲設定
Intent intent = new Intent(
RingtoneManager.ACTION_RINGTONE_PICKER);
// 型別為來電RINGTONE
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE,
RingtoneManager.TYPE_RINGTONE);
// 設定顯示的title
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE,
"設定來電鈴聲");
// 當設定完成之後返回到當前的Activity
startActivityForResult(intent, CODE_RINGSTONE);
}
}
});
mButtonAlarm.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (hasFolder(strAlarmFolder)) {
// 開啟系統鈴聲設定
Intent intent = new Intent(
RingtoneManager.ACTION_RINGTONE_PICKER);
// 設定鈴聲型別和title
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE,
RingtoneManager.TYPE_ALARM);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE,
"設定鬧鐘鈴聲");
// 當設定完成之後返回到當前的Activity
startActivityForResult(intent, CODE_ALARM);
}
}
});
mButtonNotification.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (hasFolder(strNotificationFolder)) {
// 開啟系統鈴聲設定
Intent intent = new Intent(
RingtoneManager.ACTION_RINGTONE_PICKER);
// 設定鈴聲型別和title
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE,
RingtoneManager.TYPE_NOTIFICATION);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE,
" 設定通知鈴聲");
// 當設定完成之後返回到當前的Activity
startActivityForResult(intent, CODE_NOTIFICATION);
}
}
});
}
/**
* 當設定鈴聲之後的回撥函式
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) {
return;
}
// 得到我們選擇的鈴聲
Uri pickedUri = data
.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (pickedUri != null) {
switch (requestCode) {
case CODE_RINGSTONE:
// 將我們選擇的鈴聲設定成為預設來電鈴聲
RingtoneManager.setActualDefaultRingtoneUri(this,
RingtoneManager.TYPE_RINGTONE, pickedUri);
break;
case CODE_ALARM:
// 將我們選擇的鈴聲設定成為預設鬧鐘鈴聲
RingtoneManager.setActualDefaultRingtoneUri(this,
RingtoneManager.TYPE_ALARM, pickedUri);
break;
case CODE_NOTIFICATION:
// 將我們選擇的鈴聲設定成為預設通知鈴聲
/**
* 敲黑板:黑程式碼解決Android 7.0 呼叫系統通知無法播放聲音的問題
*/
grantUriPermission("com.android.systemui", pickedUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
RingtoneManager.setActualDefaultRingtoneUri(this,
RingtoneManager.TYPE_NOTIFICATION, pickedUri);
break;
}
}
}
/**
* 檢測是否存在指定的資料夾,如果不存在則建立
*
* @param strFolder
* 資料夾路徑
*/
private boolean hasFolder(String strFolder) {
boolean btmp = false;
File f = new File(strFolder);
if (!f.exists()) {
if (f.mkdirs()) {
btmp = true;
} else {
btmp = false;
}
} else {
btmp = true;
}
return btmp;
}
}