Android個版本之間的變更
Android 6.0
執行時許可權,可以使用[PermissionDispatch][1]框架完成許可權控制,也可以自己寫程式碼,不過比較繁瑣,如下程式碼:
@RequiresApi(api = Build.VERSION_CODES.M) private void initPermission(){ permissionS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); permissionS.add(Manifest.permission.VIBRATE); permissionS.add(Manifest.permission.CAMERA); permissionS.add(Manifest.permission.ACCESS_FINE_LOCATION); if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M){ return; } ArrayList<String> needPermission = new ArrayList<>(); for(int i= 0 ; i< permissionS.size(); i++){ if(checkSelfPermission(permissionS.get(i)) != PackageManager.PERMISSION_GRANTED){ needPermission.add(permissionS.get(i)); } } if(needPermission.size() > 0){ ActivityCompat.requestPermissions(this, needPermission.toArray(new String[needPermission.size()]), 127); } //許可權處理結果回撥方法 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case PERMISSIONS_REQUEST_EXTERNAL_STORAGE: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 該許可權已經通過 } else { // 許可權已經被拒絕 } return; } } }
Android O 8.0
通知欄notification
每個應用的通知需要為其建立對應的NotificationChannel通知渠道,通知管理器為其建立渠道channel,並且每個應用通知需要設定一個NOTIFICATION_ID
如下程式碼,寫好的相容程式碼:
@RequiresApi(api = 26) private NotificationChannel createNoticationChannel(){ NotificationChannel channel = new NotificationChannel(String.valueOf(NOTIFICATION_ID), "heyichong", NotificationManager.IMPORTANCE_DEFAULT); channel.canBypassDnd();//是否繞過請勿打擾模式 channel.enableLights(true);//閃光燈 channel.setLockscreenVisibility(VISIBILITY_SECRET);//鎖屏顯示通知 channel.setLightColor(Color.RED);//閃關燈的燈光顏色 channel.canShowBadge();//桌面launcher的訊息角標 channel.enableVibration(true);//是否允許震動 channel.getAudioAttributes();//獲取系統通知響鈴聲音的配置 channel.getGroup();//獲取通知取到組 channel.setBypassDnd(true);//設定可繞過 請勿打擾模式 channel.setVibrationPattern(new long[]{100, 100, 200});//設定震動模式 channel.shouldShowLights();//是否會有燈光 return channel; } @Override public void showNotification() { Intent cancelIntent = new Intent(); cancelIntent.setAction(DownloadReceiver.INTENT_ACTION_CANCEL); PendingIntent piCancel = PendingIntent.getBroadcast(this, 0, cancelIntent, 0); mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ mBuilder = new NotificationCompat.Builder(this, String.valueOf(NOTIFICATION_ID)); mNotificationManager.createNotificationChannel(createNoticationChannel()); }else{ mBuilder = new NotificationCompat.Builder(this); mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT); } mBuilder.setContentTitle(getString(R.string.start_download)) .setTicker(getString(R.string.start_download)) //通知首次出現在通知欄,帶上升動畫效果的 .setProgress(100, 0, true) .setSmallIcon(R.mipmap.ic_launcher) .addAction(R.drawable.ic_close, getString(R.string.cancel_download), piCancel); // mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build()); /** * 設定為前臺service */ startForeground(NOTIFICATION_ID, mBuilder.build()); }
新增support-library >= 26
小於26的support庫只需要用SDK Manager更新,即可;大於則需要在Android Studio中的根build.gradle新增maven的Google庫,如下:
Android 7.0
應用間共享檔案
Android 框架強制運行了 StrictMode API 政策禁止向你的應用外公開 file:// URI。假設一項包含檔案 file:// URI型別 的 Intent 離開你的應用,應用失敗,並出現 FileUriExposedException 異常,如呼叫系統相機拍照,或裁切照片。 這時需要用FileProvider來解決該問題: 第一步:在manifest清單檔案裡註冊provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="包名.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
exported:要求必須為false,為true則會報安全異常。grantUriPermissions:true,表示授予 URI 暫時訪問許可權。
第二步:指定共享的資料夾 為了指定共享的資料夾我們須要在資源(res)資料夾下建立一個xml資料夾,然後建立一個名為“file_paths”(名字能夠隨便起,僅僅要和在manifest註冊的provider所引用的resource保持一致就可以)的資原始檔。內容例如以下:
xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path path="" name="camera_photos" />
</paths>
</resources>
代表的根資料夾: Context.getFilesDir() 代表的根資料夾: Environment.getExternalStorageDirectory() 代表的根資料夾: getCacheDir()
上述程式碼中path=”“,是有特殊意義的,它程式碼根資料夾。也就是說你能夠向其它的應用共享根資料夾及其子資料夾下不論什麼一個檔案了,假設你將path設為path=”pictures”, 那麼它代表著根資料夾下的pictures資料夾(eg:/storage/emulated/0/pictures),假設你向其它應用分享pictures資料夾範圍之外的檔案是不行的。
__第三步:使用FileProvider __ 上述準備工作做完之後,如今我們就能夠使用FileProvider了。 還是以呼叫系統相機拍照為例,我們須要將上述拍照程式碼改動為例如以下:
File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri imageUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", file);//通過FileProvider建立一個content型別的Uri
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //加入這一句表示對目標應用暫時授權該Uri所代表的檔案
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//設定Action為拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//將拍取的照片儲存到指定URI
startActivityForResult(intent,1006);
上述程式碼中主要有兩處改變:
1、將之前Uri的scheme型別為file的Uri改成了有FileProvider建立一個content型別的Uri。 2、加入了intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);來對目標應用暫時授權該Uri所代表的檔案。 [1]:https://github.com/MichaelJokAr/PermissionDispatcher