一 核心思想:
由于android7.0对私有存储的限制,导致在获取资源的时候,不能通过Uri.fromFile(..)来获取uri了,但是在写入数据的时候是可以通过Uri.fromFile(..)来获取uri的
7.0其他适配和原理讲解,这位已经讲的很清楚了分享地址:http://www.devio.org/2016/09/28/Android7.0适配心得/
二 适配后的代码段
在做照相,图片剪裁,自动安装功能适配之前,需要以下操作:
第一步,在AndroidManifest的application中添加一下代码段,作用设置存储空间可以共享
第二步,创建@xml/file_paths
(1)照相
@Override public void onClickCamera() { String status = Environment.getExternalStorageState(); if (status.equals(Environment.MEDIA_MOUNTED)) { if (!PHOTO_DIR.exists()) { PHOTO_DIR.mkdirs();// 创建照片的存储目录 } FileName = System.currentTimeMillis() + ".jpg"; mCurrentPhotoFile = new File(PHOTO_DIR, FileName); Intent intentC = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Uri imageUri = FileProvider.getUriForFile(VMAddActivity.this, "com.qqwl.fileprovider", mCurrentPhotoFile); intentC.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intentC.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); } else { intentC.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mCurrentPhotoFile)); } startActivityForResult(intentC, CAMERA_WITH_DATA); } else { Toast.makeText(VMAddActivity.this, "没有SD卡", Toast.LENGTH_LONG).show(); } }
(2)剪裁
这里有的人就会有疑问,为什么同是获取uri有些需要使用FileProvider,有些不需要呢?答案是:在访问手机资源的时候需要使用FileProvider,在不访问资源,仅仅是创建目录的时候不需要。因为7.0限制访问的是资源而不是手机存储空间。
下面是代码
/** * 裁剪图片 * * @param uri */ public void startPhotoZoom(Uri uri) { String fileName = System.currentTimeMillis() + ".jpg"; if (!PHOTO_DIR.exists()) { PHOTO_DIR.mkdirs();// 创建照片的存储目录 } mCacheFile = new File(PHOTO_DIR, fileName); Uri outputUri = Uri.fromFile(new File(mCacheFile.getPath())); String url = FileUtils.getPath(VMAddActivity.this, uri); Intent intent = new Intent("com.android.camera.action.CROP"); //sdk>=24 if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ Uri imageUri = FileProvider.getUriForFile(VMAddActivity.this, "com.qqwl.fileprovider", new File(url));//通过FileProvider创建一个content类型的Uri intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.putExtra("noFaceDetection", true);//去除默认的人脸识别,否则和剪裁匡重叠 intent.setDataAndType(imageUri, "image/*"); //19=<sdk<24 }else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT&&android.os.Build.VERSION.SDK_INT<Build.VERSION_CODES.N) { intent.setDataAndType(Uri.fromFile(new File(url)), "image/*"); //sdk<19 }else { intent.setDataAndType(uri, "image/*"); } intent.putExtra("crop", "true");// crop=true 有这句才能出来最后的裁剪页面. intent.putExtra("aspectX", 19);// 这两项为裁剪框的比例. intent.putExtra("aspectY", 20);// x:y=1:2 intent.putExtra("outputX", 600); intent.putExtra("outputY", 600); intent.putExtra("output", outputUri); intent.putExtra("outputFormat", "JPEG");// 返回格式 startActivityForResult(intent, CROP_PHOTO); }
(3)apk下载,自动安装
/** * 用来下载app的服务 */ public class DownloadService extends IntentService { private static final int BUFFER_SIZE = 10 * 1024; // 8k ~ 32K private static final String TAG = "DownloadService"; private NotificationManager mNotifyManager; private Builder mBuilder; private File apkFile; private LocalBroadcastManager lbm; private BroadcastReceiver receiver; public DownloadService() { super("DownloadService"); } @Override public void onCreate() { super.onCreate(); lbm = LocalBroadcastManager.getInstance(this); receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("com.notification.click")){ Intent installAPKIntent = new Intent(Intent.ACTION_VIEW); installAPKIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//安装完成后打开新的apk installAPKIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); installAPKIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); DownloadService.this.startActivity(installAPKIntent); android.os.Process.killProcess(android.os.Process.myPid()); } } }; lbm.registerReceiver(receiver, new IntentFilter("com.notification.click")); } @Override protected void onHandleIntent(Intent intent) { mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mBuilder = new Builder(this); String appName = getString(getApplicationInfo().labelRes); int icon = getApplicationInfo().icon; mBuilder.setContentTitle(appName).setSmallIcon(icon); //开始下载新的apk String urlStr = intent.getStringExtra("url"); InputStream in = null; FileOutputStream out = null; try { URL url = new URL(urlStr); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("GET"); urlConnection.setDoOutput(false); urlConnection.setConnectTimeout(10 * 1000); urlConnection.setReadTimeout(10 * 1000); urlConnection.setRequestProperty("Connection", "Keep-Alive"); urlConnection.setRequestProperty("Charset", "UTF-8"); urlConnection.setRequestProperty("Accept-Encoding", "gzip, deflate"); urlConnection.connect(); long bytetotal = urlConnection.getContentLength(); long bytesum = 0; int byteread = 0; in = urlConnection.getInputStream(); File dir = StorageUtils.getCacheDirectory(this); String apkName = urlStr.substring(urlStr.lastIndexOf("/") + 1, urlStr.length()); apkFile = new File(dir, apkName); out = new FileOutputStream(apkFile); byte[] buffer = new byte[BUFFER_SIZE]; int oldProgress = 0; while ((byteread = in.read(buffer)) != -1) { bytesum += byteread; out.write(buffer, 0, byteread); int progress = (int) (bytesum * 100L / bytetotal); // 如果进度与之前进度相等,则不更新,如果更新太频繁,否则会造成界面卡顿 if (progress != oldProgress) { updateProgress(progress); } oldProgress = progress; } //下载完成 mBuilder.setDefaults(Notification.DEFAULT_SOUND); mBuilder.setContentText(getString(R.string.download_success)).setProgress(0, 0, false); mNotifyManager.notify(0, mBuilder.build()); mNotifyManager.cancelAll(); //下载完成后直接安装打开 Intent installAPKIntent = new Intent(Intent.ACTION_VIEW); installAPKIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//安装完成后打开新的apk installAPKIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){ Uri fileUri = FileProvider.getUriForFile(DownloadService.this,"com.qqwl.fileprovider",apkFile); installAPKIntent.setDataAndType(fileUri, "application/vnd.android.package-archive"); }else{ installAPKIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); } this.startActivity(installAPKIntent); android.os.Process.killProcess(android.os.Process.myPid()); } catch (Exception e) { Log.e(TAG, "download apk file error", e); } finally { if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } } private void updateProgress(int progress) { //"正在下载:" + progress + "%" mBuilder.setContentText(this.getString(R.string.download_progress, progress)).setProgress(100, progress, false); //setContentInent如果不设置在4.0+上没有问题,在4.0以下会报异常 PendingIntent pendingintent = PendingIntent.getActivity(this, 0, new Intent(), PendingIntent.FLAG_CANCEL_CURRENT); mBuilder.setContentIntent(pendingintent); mNotifyManager.notify(0, mBuilder.build()); } @Override public void onDestroy() { super.onDestroy(); lbm.unregisterReceiver(receiver); } }