Search

Android - N(API 24) 的 FileUriExposedException

2016-10-01 10:43 AM

由於 Android N 加入了 intent 開啟檔案的權限判斷

所有使用 file:// 開頭的 uri 將會出現 FileUriExposedException

必須改為使用 content:// 開頭的 uri

也就是會用到 FileProvider

以下將以點擊通知開啟外部檔案為範例說明須修改的部分

首先在 res/xml 內建立一個 file_paths.xml 的檔案(名稱自訂)

程式碼範例
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <paths xmlns:android="http://schemas.android.com/apk/res/android">
  3. <external-path name="folderName" path="."/>
  4. </paths>
  5.  
  6. // external-path: 等同於 Environment.getExternalStorageDirectory()
  7. // name="folderName": 任意名稱 點擊後顯示的路徑資料夾名稱
  8. // path=".": 實際要分享權限的資料夾路徑 使用 "." 代表根目錄

建立完成後再到 AndroidManifest.xml 加入 porvider 節點

  1. <application>
  2. ...
  3.  
  4. <provider
  5. android:name="android.support.v4.content.FileProvider"
  6. android:authorities="your.package.name.fileprovider"
  7. android:exported="false"
  8. android:grantUriPermissions="true">
  9. <meta-data
  10. android:name="android.support.FILE_PROVIDER_PATHS"
  11. android:resource="@xml/file_paths" />
  12. </provider>
  13.  
  14. ...
  15. </application>

接著建立 Uri Intent

  1. Intent intent = new Intent();
  2. intent.setAction(android.content.Intent.ACTION_VIEW);
  3. intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  4.  
  5. File file = new File(dir, filename);
  6.  
  7. // API 24 之前使用的方式 會出現 FileUriExposedException
  8. // Uri.fromFile(file)
  9.  
  10. // API 24 使用的方式
  11. Uri uri = FileProvider.getUriForFile(getActivity(), "your.package.name.fileprovider", file);
  12. intent.setDataAndType(uri, MimeTypeMap.getSingleton().getMimeTypeFromExtension("html"));
  13.  
  14. int flags = PendingIntent.FLAG_UPDATE_CURRENT;
  15. PendingIntent pIntent = PendingIntent.getActivity(getActivity(), REQEUST_CODE, intent, flags);
  16.  
  17. // 取得系統的通知服務
  18. NotificationManagerCompat notificationManager = NotificationManagerCompat.from( getActivity() );
  19.  
  20. // 建立通知
  21. final Notification notification = new NotificationCompat.Builder( getActivity() )
  22. .setSmallIcon( R.drawable.ic_notification )
  23. .setLargeIcon( BitmapFactory.decodeResource(getResources(), R.drawable.ic_notification_large) )
  24. .setContentTitle( notificationTitle )
  25. .setContentText( filename )
  26. .setContentIntent(pIntent)
  27. .setOngoing(false)
  28. .setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS)
  29. .setPriority(Notification.PRIORITY_MAX)
  30. .build();
  31.  
  32. // 發送通知
  33. notificationManager.notify(NID, notification);
各項資料連結
Android - FileProvider