2016-08-31 15 views
11

główną działalnośćFileUriExposedException w Android N z kamerą

import android.Manifest; 
import android.app.Activity; 
import android.app.AlertDialog; 
import android.content.ContentResolver; 
import android.content.ContentValues; 
import android.content.Context; 
import android.content.DialogInterface; 
import android.content.Intent; 
import android.content.pm.PackageManager; 
import android.content.pm.ResolveInfo; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.net.Uri; 
import android.os.Build; 
import android.os.Environment; 
import android.os.Parcelable; 
import android.provider.MediaStore; 
import android.support.v4.app.ActivityCompat; 
import android.support.v4.content.ContextCompat; 
import android.support.v4.content.FileProvider; 
import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.View; 
import android.widget.Button; 
import android.widget.ImageView; 
import android.widget.Toast; 

import java.io.File; 

import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.io.InputStream; 
import java.text.SimpleDateFormat; 
import java.util.ArrayList; 
import java.util.Date; 
import java.util.List; 

public class MainActivity extends AppCompatActivity implements View.OnClickListener { 

    private Button mBtn; 
    private Context context; 
    private static final int SELECT_PICTURE_CAMARA = 101, SELECT_PICTURE = 201, CROP_IMAGE = 301; 
    private Uri outputFileUri; 
    String mCurrentPhotoPath; 
    private Uri selectedImageUri; 
    private File finalFile = null; 
    private ImageView imageView; 
    private PermissionUtil permissionUtil; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    mBtn = (Button) findViewById(R.id.btn_img); 
    imageView = (ImageView) findViewById(R.id.img_photo); 
    permissionUtil = new PermissionUtil(); 
    mBtn.setOnClickListener(this); 
    context = this; 
} 

@Override 
public void onClick(View view) { 
    selectImageOption(); 
} 

private void selectImageOption() { 
    final CharSequence[] items = {"Capture Photo", "Choose from Gallery", "Cancel"}; 

    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); 
    builder.setTitle("Add Photo!"); 
    builder.setItems(items, new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int item) { 
      if (items[item].equals("Capture Photo")) {     
       if (permissionUtil.checkMarshMellowPermission()) { 
        if (permissionUtil.verifyPermissions(MainActivity.this, permissionUtil.getCameraPermissions())) 
         onClickCamera(); 
        else 
         ActivityCompat.requestPermissions(MainActivity.this, permissionUtil.getCameraPermissions(), SELECT_PICTURE_CAMARA); 
       } else 
        onClickCamera(); 
      } else if (items[item].equals("Choose from Gallery")) { 
       if (permissionUtil.checkMarshMellowPermission()) { 
        if (permissionUtil.verifyPermissions(MainActivity.this, permissionUtil.getGalleryPermissions())) 
         onClickGallery(); 
        else 
         ActivityCompat.requestPermissions(MainActivity.this, permissionUtil.getGalleryPermissions(), SELECT_PICTURE); 
       } else 
        onClickGallery(); 
      } else if (items[item].equals("Cancel")) { 
       dialog.dismiss(); 
      } 
     } 
    }); 
    builder.show(); 
} 

public void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 

    if (resultCode == RESULT_OK) { 

     if (requestCode == SELECT_PICTURE) { 

      selectedImageUri = data.getData(); 
      cropImage(selectedImageUri); 

     } else if (requestCode == CROP_IMAGE) { 
      /*if (data != null) { 
       // get the returned data 
       Bundle extras = data.getExtras(); 
       // get the cropped bitmap 
       Bitmap selectedBitmap = extras.getParcelable("data"); 

       imageView.setImageBitmap(selectedBitmap); 
      }*/ 

      Uri imageUri = Uri.parse(mCurrentPhotoPath); 
      File file = new File(imageUri.getPath()); 
      try { 
       InputStream ims = new FileInputStream(file); 
       imageView.setImageBitmap(BitmapFactory.decodeStream(ims)); 
      } catch (FileNotFoundException e) { 
       return; 
      } 

     } else if (requestCode == SELECT_PICTURE_CAMARA && resultCode == Activity.RESULT_OK) { 
      cropImage(Uri.parse(mCurrentPhotoPath)); 

     } 
    } 
} 

private void onClickCamera() { 
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 

    if (takePictureIntent.resolveActivity(context.getPackageManager()) != null) { 
     File photoFile = null; 
     try { 
      photoFile = createImageFile(); 
     } catch (IOException ex) { 
     } 
     if (photoFile != null) { 

      Uri photoURI; 
      if (Build.VERSION.SDK_INT >= 24) { 
       photoURI = FileProvider.getUriForFile(MainActivity.this, 
         BuildConfig.APPLICATION_ID + ".provider", photoFile); 
      } else { 
       photoURI = Uri.fromFile(photoFile); 
      } 

      takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); 
      startActivityForResult(takePictureIntent, SELECT_PICTURE_CAMARA); 

     } 
    } 
} 

private void onClickGallery() { 
    List<Intent> targets = new ArrayList<>(); 
    Intent intent = new Intent(); 
    intent.setType("image/*"); 
    intent.setAction(Intent.ACTION_PICK); 
    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true); 
    List<ResolveInfo> candidates = getApplicationContext().getPackageManager().queryIntentActivities(intent, 0); 

    for (ResolveInfo candidate : candidates) { 
     String packageName = candidate.activityInfo.packageName; 
     if (!packageName.equals("com.google.android.apps.photos") && !packageName.equals("com.google.android.apps.plus") && !packageName.equals("com.android.documentsui")) { 
      Intent iWantThis = new Intent(); 
      iWantThis.setType("image/*"); 
      iWantThis.setAction(Intent.ACTION_PICK); 
      iWantThis.putExtra(Intent.EXTRA_LOCAL_ONLY, true); 
      iWantThis.setPackage(packageName); 
      targets.add(iWantThis); 
     } 
    } 
    if (targets.size() > 0) { 
     Intent chooser = Intent.createChooser(targets.remove(0), "Select Picture"); 
     chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targets.toArray(new Parcelable[targets.size()])); 
     startActivityForResult(chooser, SELECT_PICTURE); 
    } else { 
     Intent intent1 = new Intent(Intent.ACTION_PICK); 
     intent1.setType("image/*"); 
     startActivityForResult(Intent.createChooser(intent1, "Select Picture"), SELECT_PICTURE); 
    } 
} 

private File createImageFile() throws IOException { 
    // Create an image file name 
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
    String imageFileName = "JPEG_" + timeStamp + "_"; 

    File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); 
    File image = File.createTempFile(
      imageFileName, /* prefix */ 
      ".jpg",   /* suffix */ 
      storageDir  /* directory */ 
    ); 

    // Save a file: path for use with ACTION_VIEW intents 
    if (Build.VERSION.SDK_INT >= 24) { 
     mCurrentPhotoPath = String.valueOf(FileProvider.getUriForFile(MainActivity.this, 
       BuildConfig.APPLICATION_ID + ".provider", image)); 
    } else { 
     mCurrentPhotoPath = String.valueOf(Uri.fromFile(image)); 
    } 

    return image; 
} 

private void cropImage(Uri selectedImageUri) { 
    Intent cropIntent = new Intent("com.android.camera.action.CROP"); 

    cropIntent.setDataAndType(selectedImageUri, "image/*"); 

    cropIntent.putExtra("crop", "true"); 
    cropIntent.putExtra("aspectX", 1); 
    cropIntent.putExtra("aspectY", 1.5); 
    cropIntent.putExtra("return-data", true); 

    outputFileUri = Uri.fromFile(createCropFile()); 

    cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); 
    startActivityForResult(cropIntent, CROP_IMAGE); 
} 

private File createCropFile() { 
    File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); 
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
    // path = path + (timeStamp + "1jpg"); 
    File file = null; 
    try { 
     file = File.createTempFile(timeStamp, ".jpg", storageDir); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    mCurrentPhotoPath = String.valueOf(Uri.fromFile(file)); 
    return file; 
} 
} 

PermissionUtil.java

package com.example.shwetachauhan.imagecropasoebi; 

import android.content.Context; 
import android.content.pm.PackageManager; 
import android.os.Build; 
import android.support.v4.app.ActivityCompat; 

public class PermissionUtil { 
    private String[] galleryPermissions = { 
     "android.permission.WRITE_EXTERNAL_STORAGE", 
     "android.permission.READ_EXTERNAL_STORAGE" 
}; 

private String[] cameraPermissions = { 
     "android.permission.CAMERA", 
     "android.permission.WRITE_EXTERNAL_STORAGE", 
     "android.permission.READ_EXTERNAL_STORAGE" 
}; 

public String[] getGalleryPermissions(){ 
    return galleryPermissions; 
} 

public String[] getCameraPermissions() { 
    return cameraPermissions; 
} 

public boolean verifyPermissions(int[] grantResults) { 
    if(grantResults.length < 1){ 
     return false; 
    } 

    for (int result : grantResults) { 
     if (result != PackageManager.PERMISSION_GRANTED) { 
      return false; 
     } 
    } 
    return true; 
} 

public boolean verifyPermissions(Context context, String[] grantResults) { 
    for (String result : grantResults) { 
     if (ActivityCompat.checkSelfPermission(context, result) != PackageManager.PERMISSION_GRANTED) { 
      return false; 
     } 
    } 
    return true; 
} 

public boolean checkMarshMellowPermission(){ 
    return(Build.VERSION.SDK_INT> Build.VERSION_CODES.LOLLIPOP_MR1); 
} 

public boolean checkJellyBean(){ 
    return(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN); 
} 
} 
  • Ten kod jest do odbioru obrazu z kamery do wysiewania lub galerii
  • Ten kod działa dla wszystkich systemów Android, ale kiedy próbuję uruchomić On A Urządzenie ndroid N ulega awarii po otwarciu aparatu. Działa dobrze w Androidzie N z galerią.
+0

Wklej Error Błąd Log –

Odpowiedz

30

Mam również w obliczu tego samego problemu w urządzeń Android N. Ale ja to rozwiązałem.

Oto mój kod, który może rozwiązać ten problem:

public void launchCamera() { 
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { 
     intent.putExtra(MediaStore.EXTRA_OUTPUT, getPhotoFileUri()); 
    } else { 
     File file = new File(getPhotoFileUri().getPath()); 
     Uri photoUri = FileProvider.getUriForFile(getApplicationContext(), getApplicationContext().getPackageName() + ".provider", file); 
     intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); 
    } 
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 
    if (intent.resolveActivity(getApplicationContext().getPackageManager()) != null) { 
     startActivityForResult(intent, REQUEST_CAMERA); 
    } 
} 

Następnie należy utworzyć folder XML w OZE, w tym folderze trzeba utworzyć xml oznaczone provider_paths.xml

kod w provider_paths.xml

<?xml version="1.0" encoding="utf-8"?> 
<paths xmlns:android="http://schemas.android.com/apk/res/android"> 
<external-path name="external_files" path="."/> 
</paths> 

Później oczywistego trzeba dodać następujące wewnątrz znacznika aplikacji i upewnij się, że compileSdkVersion> = 24

<provider 
android:name="android.support.v4.content.FileProvider" 
android:authorities="${applicationId}.provider" 
android:exported="false" 
android:grantUriPermissions="true"> 
<meta-data 
android:name="android.support.FILE_PROVIDER_PATHS" 
android:resource="@xml/provider_paths"/> 
</provider> 

Oto dwa linki referencyjne, które mogą Cię lepiej na lepsze zrozumienie.

Linki:

link1 - od średniej współpracy

link2 - od inthecheesefactory

+1

Karthik, wysłałeś odpowiedź w dobry sposób. Pomogło mi to. –

+0

Zgadzam się z @AnshulTyagi. Dziękujemy –

+1

To powinno być zaakceptowane odpowiedź –

3

Z Androida N, Android zmienił sposób podawania identyfikatora URI pliku. Używanie pliku: // uri jest zabronione i rzuciłoby to. Użyj opcji FileProvider, aby to rozwiązać.

Przekazywanie pliku: // identyfikatory URI spoza domeny pakietowej mogą pozostawić odbiornik w niedostępnej ścieżce. Dlatego próby przekazania pliku: // URI wyzwalają wyjątek FileUriExposedException. Zalecanym sposobem udostępniania zawartości prywatnego pliku jest użycie FileProvider.

Więcej informacji można znaleźć here

+3

Pomocna związek z pełne wyjaśnienie, jak to naprawić: https://inthecheesefactory.com/blog/how-to-share-access-to-file-with- fileprovider-na-android-nougat/pl – Jonas

5

Jeśli nie dotykają innych aplikacji w systemie wystarczy umieścić

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); 
StrictMode.setVmPolicy(builder.build()); 

w twoim Application.onCreate().Zignoruje to ekspozycję URI i jesteś gotowy.

-4

zmiana ur buildToolsVersion

buildToolsVersion "25.0.1" 

do

buildToolsVersion "23.0.1" 
+0

Obniżanie poziomu buildToolsVersions nie jest dobrym rozwiązaniem. Po prostu ukrywa problem. –

+0

Dlaczego warto zmienić wersję narzędzia do tworzenia aplikacji? –

0

Można wykorzystać StrictMode, dodać poniżej kodu do swojej działalności onCreate()

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); 
    StrictMode.setVmPolicy(builder.build()); 
Powiązane problemy