2016-08-31 2 views
11

MainActivityFileUriExposedException in Android N mit Kamera

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); 
} 
} 
  • Dieser Code ist für für Erntebergungs Bild von Kamera oder Galerie
  • Dieser Code funktioniert für alle Android-Betriebssysteme, aber wenn ich versuche, auf A zu laufen ndroid N Gerät stürzt es ab, wenn ich die Kamera öffne. Es funktioniert gut in Android N mit Galerie.
+0

Paste Fehler Absturz Log –

Antwort

30

ich konfrontiert auch das gleiche Problem in Android N-Geräten. Aber ich habe es gelöst.

Hier ist mein Code, um das Problem zu lösen:

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); 
    } 
} 

Danach benötigen Sie einen XML Ordner in res zu erstellen, und in diesem Ordner benötigen Sie eine xml provider_paths.xml etikettiert erstellen

-Code in 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> 

Später in Manifest müssen Sie die folgende in der Anwendung Tag und stellen Sie sicher, dass die 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> 

Hier sind die beiden Referenz Links hinzufügen, die Sie besser für besser leiten können Verstehen.

Links:

link1 - von den Mitteln Zusammenarbeit

link2 - von inthecheesefactory

+1

Karthik, du hast die Antwort gut geschrieben. Es hat mir geholfen. –

+0

Ich stimme @AnshulTyagi zu. Danke –

+1

Dies sollte akzeptiert werden Antwort –

3

Von Android N hat Android die Art und Weise geändert, wie Sie eine Datei-URI bereitstellen. Verwenden von file: // uri ist verboten und würde dies werfen. Verwenden Sie die FileProvider, um dies zu überwinden.

Übergeben von Datei: // URIs außerhalb der Paketdomäne können den Empfänger mit einem nicht zugänglichen Pfad verlassen. Daher lösen Versuche, eine Datei: // URI zu übergeben, eine FileUriExposedException aus. Die empfohlene Methode zum Freigeben des Inhalts einer privaten Datei besteht in der Verwendung des FileProvider.

Weitere Daten können here

+3

Hilfreiche Link mit vollständige Erklärung, wie Sie dies beheben können: https://inthecheesefactory.com/blog/how-to-share-access-to-file-with- fileprovider-on-android-nougat/de – Jonas

5

Wenn Sie noch keine anderen Anwendungen im System zu berühren sind gerade auf

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

in Ihrem Application.onCreate().Es wird die URI-Exposition ignorieren und Sie sind gut zu gehen.

-4

Änderung ur buildToolsVersion

buildToolsVersion "25.0.1" 

zu

buildToolsVersion "23.0.1" 
+0

Downgrade der buildToolsVersions ist keine gute Lösung. Es verbirgt nur das Problem. –

+0

Warum die Build-Tool-Version der App ändern? –

0

Sie können StrictMode verwenden, unter Code in Ihre Aktivität hinzufügen onCreate()

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