µ÷ÓÃϵͳÏà»ú¡¢Ïà²á¡¢¼ô²ÃͼƬ²¢ÉÏ´«£¨³£ÓÃÓÚÉÏ´«Í·Ïñ£¬¼æÈÝAndroid7.0£©

hansion / ÎÄ ·¢±íÓÚ2017-11-02 15:00 µÚ´ÎÔĶÁ µ÷,µ÷ÓÃÏà»ú,ÉÏ´«Í¼Æ¬,Ñ¡ÔñÍ·Ïñ

HansionµÄ²©¿Í

Demo githubµØÖ·


ÓÉÓÚÔÚAndroid 7.0 ²ÉÓÃÁËStrictMode APIÕþ²ß½û£¬ÆäÖÐÓÐÒ»ÌõÏÞÖÆ¾ÍÊǶÔĿ¼·ÃÎʵÄÏÞÖÆ¡£

ÕâÏî±ä¸üÒâζ×ÅÎÒÃÇÎÞ·¨Í¨¹ýFile API·ÃÎÊÊÖ»ú´æ´¢ÉϵÄÊý¾Ý£¬Ò²¾ÍÊÇ˵£¬¸øÆäËûÓ¦Óô«µÝ file:// URI ÀàÐ͵ÄUri£¬¿ÉÄܻᵼÖ½ÓÊÜÕßÎÞ·¨·ÃÎʸ÷¾¶£¬²¢ÇÒ»á»á´¥·¢ FileUriExposedExceptionÒì³£¡£

StrictMode APIÕþ²ß½ûÖеÄÓ¦Óü乲ÏíÎļþ¾ÍÊǶÔÉÏÊöÏÞÖÆµÄÓ¦¶Ô·½·¨£¬ËüÖ¸Ã÷ÁËÎÒÃÇÔÚÔÚÓ¦Óü乲ÏíÎļþ¿ÉÒÔ·¢ËÍ content:// URIÀàÐ͵ÄUri£¬²¢ÊÚÓè URI ÁÙʱ·ÃÎÊȨÏÞ£¬¼´Ê¹ÓÃFileProvider

½ÓÏÂÀ´£¬ÎÒÃÇʹÓÃFileProviderʵÏÖµ÷ÓÃϵͳÏà»ú¡¢Ïà²á¡¢¼ô²ÃͼƬµÄ¹¦ÄܼæÈÝAndroid 7.0

µÚÒ»²½£ºFileProviderÏà¹Ø×¼±¸¹¤×÷

  • ÔÚAndroidManifest.xmlÖÐÔö¼Óprovider½Úµã£¬ÈçÏ£º
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.hansion.chosehead"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>

ÆäÖУº android:authorities ±íʾÊÚȨÁÐ±í£¬ÌîдÄãµÄÓ¦ÓðüÃû£¬µ±Óжà¸öÊÚȨʱ£¬Ó÷ֺŸô¿ª android:exported ±íʾ¸ÃÄÚÈÝÌṩÆ÷(ContentProvider)ÊÇ·ñÄܱ»µÚÈý·½³ÌÐò×é¼þʹÓ㬱ØÐëΪfalse£¬·ñÔò»á±¨Òì³££ºava.lang.RuntimeException: Unable to get provider android.support.v4.content.FileProvider: java.lang.SecurityException: Provider must not be exported android:grantUriPermissions="true" ±íʾÊÚÓè URI ÁÙʱ·ÃÎÊȨÏÞ android:resource ÊôÐÔÖ¸ÏòÎÒÃÇ×Ô¼°´´½¨µÄxmlÎļþµÄ·¾¶£¬ÎļþÃûËæ±ãÆð

  • ½ÓÏÂÀ´£¬ÎÒÃÇÐèÒªÔÚ×ÊÔ´(res)Ŀ¼Ï´´½¨Ò»¸öxmlĿ¼£¬²¢½¨Á¢Ò»¸öÒÔÉÏÃæÃû×ÖΪÎļþÃûµÄxmlÎļþ£¬ÄÚÈÝÈçÏ£º
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path path="" name="image" />
</paths>

ÆäÖУº external-path ´ú±í¸ùĿ¼Ϊ: Environment.getExternalStorageDirectory() £¬Ò²¿ÉÒÔдÆäËûµÄ£¬È磺 files-path ´ú±í¸ùĿ¼Ϊ:Context.getFilesDir() cache-path ´ú±í¸ùĿ¼Ϊ:getCacheDir() ÆäpathÊôÐÔµÄÖµ´ú±í·¾¶ºó²ã¼¶Ãû³Æ£¬Îª¿ÕÔò´ú±í¾ÍÊǸùĿ¼£¬¼ÙÈçΪ¡°pictures¡±,¾Í´ú±í¶ÔÓ¦¸ùĿ¼ÏµÄpicturesĿ¼

µÚ¶þ²½£ºÊ¹ÓÃFileProvider

  • ÔÚÕâ֮ǰ£¬ÎÒÃÇÐèÒªÔÚAndroidManifest.xmlÖÐÔö¼Ó±ØÒªµÄ¶ÁдȨÏÞ£º
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

1. ͨ¹ýÏà»ú»ñȡͼƬ

ÔÚͨ¹ýIntentÌø×ªÏµÍ³Ïà»úǰ£¬ÎÒÃÇÐèÒª¶Ô°æ±¾½øÐÐÅжϣ¬Èç¹ûÔÚAndroid7.0ÒÔÉÏ,ʹÓÃFileProvider»ñÈ¡Uri£¬´úÂëÈçÏ£º

    /**
     * ´ÓÏà»ú»ñȡͼƬ
     */
    private void getPicFromCamera() {
        //ÓÃÓÚ±£´æµ÷ÓÃÏà»úÅÄÕÕºóËùÉú³ÉµÄÎļþ
        tempFile = new File(Environment.getExternalStorageDirectory().getPath(), System.currentTimeMillis() + ".jpg");
        //Ìø×ªµ½µ÷ÓÃϵͳÏà»ú
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //Åжϰ汾
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {   //Èç¹ûÔÚAndroid7.0ÒÔÉÏ,ʹÓÃFileProvider»ñÈ¡Uri
            intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(MainActivity.this, "com.hansion.chosehead", tempFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
        } else {    //·ñÔòʹÓÃUri.fromFile(file)·½·¨»ñÈ¡Uri
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
        }
        startActivityForResult(intent, CAMERA_REQUEST_CODE);
    }

Èç¹ûÄãºÃÆæÍ¨¹ýFileProvider»ñÈ¡µÄUriÊÇʲôÑùµÄ£¬¿ÉÒÔ´òÓ¡³öÀ´¿´Ò»¿´£¬ÀýÈ磺

content://com.hansion.chosehead/image/1509356493642.jpg

ÆäÖУº com.hansion.chosehead ÊÇÎҵİüÃû image ÊÇÉÏÎÄÖÐxmlÎļþÖеÄnameÊôÐÔµÄÖµ 1509356493642.jpg ÊÇÎÒ´´½¨µÄͼƬµÄÃû×Ö Ò²¾ÍÊÇ˵£¬content://com.hansion.chosehead/image/ ´ú±íµÄ¾ÍÊǸùĿ¼

2.ͨ¹ýÏà²á»ñȡͼƬ

    /**
     * ´ÓÏà²á»ñȡͼƬ
     */
    private void getPicFromAlbm() {
        Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
        photoPickerIntent.setType("image/*");
        startActivityForResult(photoPickerIntent, ALBUM_REQUEST_CODE);
    }

3.¼ô²ÃͼƬ

    /**
     * ²Ã¼ôͼƬ
     */
    private void cropPhoto(Uri uri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);
        intent.putExtra("return-data", true);
        startActivityForResult(intent, CROP_REQUEST_CODE);
    }

ÉÏÎÄÖУ¬Äã»á·¢ÏÖ£¬ÎÒÃÇÖ»¶ÔUri½øÐÐÁËÌØÊâ´¦Àí¡£Ã»´í£¬Õâ¾ÍÊǺËÐı仯

µÚÈý²½£º½ÓÊÕͼƬÐÅÏ¢

  • ÎÒÃÇÔÚonActivityResult·½·¨ÖлñµÃ·µ»ØµÄͼƬÐÅÏ¢,ÔÚÕâÀïÎÒÃÇ»áÏȵ÷Óüô²ÃÈ¥¼ô²ÃͼƬ,È»ºó¶Ô¼ô²Ã·µ»ØµÄͼƬ½øÐÐÉèÖᢱ£´æ¡¢ÉÏ´«µÈ²Ù×÷
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        switch (requestCode) {
            case CAMERA_REQUEST_CODE:   //µ÷ÓÃÏà»úºó·µ»Ø
                if (resultCode == RESULT_OK) {
                    //ÓÃÏà»ú·µ»ØµÄÕÕÆ¬È¥µ÷Óüô²ÃÒ²ÐèÒª¶ÔUri½øÐд¦Àí
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        Uri contentUri = FileProvider.getUriForFile(MainActivity.this, "com.hansion.chosehead", tempFile);
                        cropPhoto(contentUri);
                    } else {
                        cropPhoto(Uri.fromFile(tempFile));
                    }
                }
                break;
            case ALBUM_REQUEST_CODE:    //µ÷ÓÃÏà²áºó·µ»Ø
                if (resultCode == RESULT_OK) {
                    Uri uri = intent.getData();
                    cropPhoto(uri);
                }
                break;
            case CROP_REQUEST_CODE:     //µ÷Óüô²Ãºó·µ»Ø
                Bundle bundle = intent.getExtras();
                if (bundle != null) {
                    //ÔÚÕâÀï»ñµÃÁ˼ô²ÃºóµÄBitmap¶ÔÏ󣬿ÉÒÔÓÃÓÚÉÏ´«
                    Bitmap image = bundle.getParcelable("data");
                    //ÉèÖõ½ImageViewÉÏ
                    mHeader_iv.setImageBitmap(image);
                    //Ò²¿ÉÒÔ½øÐÐһЩ±£´æ¡¢Ñ¹ËõµÈ²Ù×÷ºóÉÏ´«
//                    String path = saveImage("crop", image);
                }
                break;
        }
    }
  • ±£´æBitmapµ½±¾µØµÄ·½·¨£º
    public String saveImage(String name, Bitmap bmp) {
        File appDir = new File(Environment.getExternalStorageDirectory().getPath());
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        String fileName = name + ".jpg";
        File file = new File(appDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
            fos.flush();
            fos.close();
            return file.getAbsolutePath();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

ÖÁ´Ë£¬¶ÔAndroid7.0µÄ¼æÈݾͽáÊøÁË ×ܽáһϣ¬ÔÚµ÷ÓÃÏà»úºÍ¼ô²Ãʱ£¬´«ÈëµÄUriÐèҪʹÓÃFileProviderÀ´»ñÈ¡


ÍêÕû´úÂ룺

  • MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private ImageView mHeader_iv;
    //Ïà²áÇëÇóÂë
    private static final int ALBUM_REQUEST_CODE = 1;
    //Ïà»úÇëÇóÂë
    private static final int CAMERA_REQUEST_CODE = 2;
    //¼ô²ÃÇëÇóÂë
    private static final int CROP_REQUEST_CODE = 3;
    //µ÷ÓÃÕÕÏà»ú·µ»ØÍ¼Æ¬Îļþ
    private File tempFile;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }
    private void initView() {
        mHeader_iv = (ImageView) findViewById(R.id.mHeader_iv);
        Button mGoCamera_btn = (Button) findViewById(R.id.mGoCamera_btn);
        Button mGoAlbm_btn = (Button) findViewById(R.id.mGoAlbm_btn);
        mGoCamera_btn.setOnClickListener(this);
        mGoAlbm_btn.setOnClickListener(this);
    }
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.mGoCamera_btn:
                getPicFromCamera();
                break;
            case R.id.mGoAlbm_btn:
                getPicFromAlbm();
                break;
            default:
                break;
        }
    }
    /**
     * ´ÓÏà»ú»ñȡͼƬ
     */
    private void getPicFromCamera() {
        //ÓÃÓÚ±£´æµ÷ÓÃÏà»úÅÄÕÕºóËùÉú³ÉµÄÎļþ
        tempFile = new File(Environment.getExternalStorageDirectory().getPath(), System.currentTimeMillis() + ".jpg");
        //Ìø×ªµ½µ÷ÓÃϵͳÏà»ú
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //Åжϰ汾
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {   //Èç¹ûÔÚAndroid7.0ÒÔÉÏ,ʹÓÃFileProvider»ñÈ¡Uri
            intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(MainActivity.this, "com.hansion.chosehead", tempFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
            Log.e("dasd", contentUri.toString());
        } else {    //·ñÔòʹÓÃUri.fromFile(file)·½·¨»ñÈ¡Uri
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
        }
        startActivityForResult(intent, CAMERA_REQUEST_CODE);
    }
    /**
     * ´ÓÏà²á»ñȡͼƬ
     */
    private void getPicFromAlbm() {
        Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
        photoPickerIntent.setType("image/*");
        startActivityForResult(photoPickerIntent, ALBUM_REQUEST_CODE);
    }
    /**
     * ²Ã¼ôͼƬ
     */
    private void cropPhoto(Uri uri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);
        intent.putExtra("return-data", true);
        startActivityForResult(intent, CROP_REQUEST_CODE);
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        switch (requestCode) {
            case CAMERA_REQUEST_CODE:   //µ÷ÓÃÏà»úºó·µ»Ø
                if (resultCode == RESULT_OK) {
                    //ÓÃÏà»ú·µ»ØµÄÕÕÆ¬È¥µ÷Óüô²ÃÒ²ÐèÒª¶ÔUri½øÐд¦Àí
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        Uri contentUri = FileProvider.getUriForFile(MainActivity.this, "com.hansion.chosehead", tempFile);
                        cropPhoto(contentUri);
                    } else {
                        cropPhoto(Uri.fromFile(tempFile));
                    }
                }
                break;
            case ALBUM_REQUEST_CODE:    //µ÷ÓÃÏà²áºó·µ»Ø
                if (resultCode == RESULT_OK) {
                    Uri uri = intent.getData();
                    cropPhoto(uri);
                }
                break;
            case CROP_REQUEST_CODE:     //µ÷Óüô²Ãºó·µ»Ø
                Bundle bundle = intent.getExtras();
                if (bundle != null) {
                    //ÔÚÕâÀï»ñµÃÁ˼ô²ÃºóµÄBitmap¶ÔÏ󣬿ÉÒÔÓÃÓÚÉÏ´«
                    Bitmap image = bundle.getParcelable("data");
                    //ÉèÖõ½ImageViewÉÏ
                    mHeader_iv.setImageBitmap(image);
                    //Ò²¿ÉÒÔ½øÐÐһЩ±£´æ¡¢Ñ¹ËõµÈ²Ù×÷ºóÉÏ´«
//                    String path = saveImage("crop", image);
                }
                break;
        }
    }
    public String saveImage(String name, Bitmap bmp) {
        File appDir = new File(Environment.getExternalStorageDirectory().getPath());
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        String fileName = name + ".jpg";
        File file = new File(appDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
            fos.flush();
            fos.close();
            return file.getAbsolutePath();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:padding="5dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="30dp"
        android:text="Ñ¡ÔñÍ·Ïñ"
        android:textSize="18sp" />
    <ImageView
        android:id="@+id/mHeader_iv"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="50dp"
        android:src="@mipmap/ic_launcher" />
    <android.support.v4.widget.Space
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>
    <Button
        android:id="@+id/mGoCamera_btn"
        android:text="ÅÄÕÕÑ¡Ôñ"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/mGoAlbm_btn"
        android:text="±¾µØÏà²áÑ¡Ôñ"
        android:layout_marginBottom="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

±¾ÎÄ»¹Óжദ¿ÉÓÅ»¯µÄµØ·½£¬±ÈÈçAndroid 6.0ÒÔÉ϶¯Ì¬È¨Ï޵ĻñÈ¡¡¢±£´æÍ¼Æ¬Ç°¶ÔSD¿¨ÊÇ·ñ¿ÉÓõÄÅжϡ¢ÈÝ´í´ëÊ©µÈµÈ¡£ÕâЩ¶¼ÊDz»ÊôÓÚ±¾ÎĵÄÖ÷ÒªÄÚÈÝ£¬±¾ÎľͲ»ÔÙ¶à˵ÁË¡£ Æäʵ»¹ÓÐһЩƫÃŵķ½·¨£¬²»¹ý±¾ÈËÊDz»ÌᳫµÄ£¬±ÈÈçÏÂÎÄ×Ô¼º´¦ÀíStrictModeÑÏ¿Áģʽ¡¢»òÕß½«targetSdkVersion¸ÄΪ24ÒÔϵȷ½·¨£¬ÕâЩ¶¼ÊÇÎ¥±³¿ª·¢Ë¼ÏëµÄ·½·¨£¬×îºÃ²»ÒªÊ¹Óá£

        //½¨ÒéÔÚapplication µÄonCreate()µÄ·½·¨Öе÷ÓÃ
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy(builder.build());
        }