android.os.FileUriExposedException: file:///storage/emulated/0/Pictures/picFolder/1.jpg exposed beyond app through ClipData.Item.getUri()

匿名 (未验证) 提交于 2019-12-03 08:33:39

问题:

I am trying to take a photo from the phone's camera using this code:

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="fill_parent"     android:layout_height="fill_parent"     android:orientation="vertical" >      <Button         android:id="@+id/btnCapture"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:text="Camera" />  </LinearLayout> 

MainActivity.java:

public class CameraDemoActivity extends Activity {     int TAKE_PHOTO_CODE = 0;     public static int count = 0;      /** Called when the activity is first created. */     @Override     public void onCreate(Bundle savedInstanceState)     {         super.onCreate(savedInstanceState);         setContentView(R.layout.main);          // Here, we are making a folder named picFolder to store         // pics taken by the camera using this application.         final String dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/picFolder/";         File newdir = new File(dir);         newdir.mkdirs();          Button capture = (Button) findViewById(R.id.btnCapture);         capture.setOnClickListener(new View.OnClickListener() {             public void onClick(View v) {                  // Here, the counter will be incremented each time, and the                 // picture taken by camera will be stored as 1.jpg,2.jpg                 // and likewise.                 count++;                 String file = dir+count+".jpg";                 File newfile = new File(file);                 try {                     newfile.createNewFile();                 }                 catch (IOException e)                 {                 }                  Uri outputFileUri = Uri.fromFile(newfile);                  Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);                 cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);                  startActivityForResult(cameraIntent, TAKE_PHOTO_CODE);             }         });     }      @Override     protected void onActivityResult(int requestCode, int resultCode, Intent data) {         super.onActivityResult(requestCode, resultCode, data);          if (requestCode == TAKE_PHOTO_CODE && resultCode == RESULT_OK) {             Log.d("CameraDemo", "Pic saved");         }     } } 

I also added these permissions to Manifest.xml:

<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

But I get this error message:

android.os.FileUriExposedException: file:///storage/emulated/0/Pictures/picFolder/1.jpg exposed beyond app through ClipData.Item.getUri()

What is the problem and how can I fix it?

EDIT: this is the updated code:

MainActivity:

package com.m.textdetection;  import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.icu.text.SimpleDateFormat; import android.net.Uri; import android.os.Environment; 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 java.io.File; import java.io.IOException; import java.util.Date;  public class MainActivity extends AppCompatActivity {      private MyTessOCR mTessOCR = new MyTessOCR(MainActivity.this);      private Button takePictureButton;     private ImageView imageView;       /*     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          takePictureButton = (Button) findViewById(R.id.button_image);         imageView = (ImageView) findViewById(R.id.imageview);          if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {             takePictureButton.setEnabled(false);             ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE }, 0);         }     }       @Override     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {         if (requestCode == 0) {             if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED                     && grantResults[1] == PackageManager.PERMISSION_GRANTED) {                 takePictureButton.setEnabled(true);             }         }     }      public void takePicture(View view) {         Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);         file = Uri.fromFile(getOutputMediaFile());         intent.putExtra(MediaStore.EXTRA_OUTPUT, file);          startActivityForResult(intent, 100);     }      @Override     protected void onActivityResult(int requestCode, int resultCode, Intent data)     {         if (requestCode == 100) {             if (resultCode == RESULT_OK) {                 imageView.setImageURI(File);             }         }     }      private static File getOutputMediaFile(){         File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(                 Environment.DIRECTORY_PICTURES), "CameraDemo");          if (!mediaStorageDir.exists()){             if (!mediaStorageDir.mkdirs()){                 return null;             }         }          String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());         return new File(mediaStorageDir.getPath() + File.separator +                 "IMG_"+ timeStamp + ".jpg");     }     */       int TAKE_PHOTO_CODE = 0;     public static int count = 0;       @Override     protected void onCreate(Bundle savedInstanceState)     {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          final String dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/picFolder/";         File newdir = new File(dir);         newdir.mkdirs();          Button capture = (Button) findViewById(R.id.btnCapture);         capture.setOnClickListener(new View.OnClickListener() {             public void onClick(View v) {                  // Here, the counter will be incremented each time, and the                 // picture taken by camera will be stored as 1.jpg,2.jpg                 // and likewise.                 count++;                 String file = dir+count+".jpg";                 File newfile = new File(file);                 try {                     newfile.createNewFile();                 }                 catch (IOException e)                 {                 }             //     Uri outputFileUri = Uri.fromFile(newfile);                 Uri outputFileUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID, newfile);                  Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);                 cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);                  startActivityForResult(cameraIntent, TAKE_PHOTO_CODE);             }         });       }          @Override     protected void onActivityResult(int requestCode, int resultCode, Intent data)     {         super.onActivityResult(requestCode, resultCode, data);          if (requestCode == TAKE_PHOTO_CODE && resultCode == RESULT_OK) {             Log.d("CameraDemo", "Pic saved");         }     }       private void doOCR()     {      //   String temp = mTessOCR.getOCRResult(bitmap);      } } 

Manifest:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     package="com.m.textdetection">      <uses-permission android:name="android.permission.CAMERA"/>     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>      <application         android:allowBackup="true"         android:icon="@mipmap/ic_launcher"         android:label="@string/app_name"         android:roundIcon="@mipmap/ic_launcher_round"         android:supportsRtl="true"         android:theme="@style/AppTheme">         <activity android:name=".MainActivity">             <intent-filter>                 <action android:name="android.intent.action.MAIN" />                  <category android:name="android.intent.category.LAUNCHER" />             </intent-filter>         </activity>          <provider             android:name="android.support.v4.content.FileProvider"             android:authorities="${applicationId}.my.package.name.provider"             android:exported="false"             android:grantUriPermissions="true"             tools:replace="android:authorities">             <meta-data                 android:name="android.support.FILE_PROVIDER_PATHS"                 android:resource="@xml/provider_paths"                 tools:replace="android:resource"/>         </provider>      </application>  </manifest> 

build.gradle(app):

apply plugin: 'com.android.application'  android {     compileSdkVersion 27     buildToolsVersion "27.0.3"     defaultConfig {         applicationId "com.m.textdetection"         minSdkVersion 21         targetSdkVersion 27         versionCode 1         versionName "1.0"         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"     }     buildTypes {         release {             minifyEnabled false             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'         }     } }  dependencies {     compile fileTree(dir: 'libs', include: ['*.jar'])     androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {         exclude group: 'com.android.support', module: 'support-annotations'     })     compile 'com.android.support:appcompat-v7:27.0.2'     compile 'com.android.support.constraint:constraint-layout:1.0.2'     testCompile 'junit:junit:4.12'      compile 'com.rmtheis:tess-two:6.0.3'     compile 'com.android.support:support-v4:27.0.2'  } 

And this is the new error:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference

Occurs in this line:

        Uri outputFileUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID, newfile); 

Edir2:

package com.m.textdetection;   import android.content.Context; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.os.Environment; import android.util.Log;  import com.googlecode.tesseract.android.TessBaseAPI;  import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream;  public class MyTessOCR {     private String datapath;     private TessBaseAPI mTess;     Context context;     public MyTessOCR(Context context)     {         this.context = context;         datapath = Environment.getExternalStorageDirectory() + "/ocrctz/";         File dir = new File(datapath + "/tessdata/");         File file = new File(datapath + "/tessdata/" + "eng.traineddata");         if (!file.exists())         {             Log.d("mylog", "in file doesn't exist");             dir.mkdirs();             copyFile(context);         }          mTess = new TessBaseAPI();         String language = "eng";         mTess.init(datapath, language);         //Auto only         mTess.setPageSegMode(TessBaseAPI.PageSegMode.PSM_AUTO_ONLY);     }      public void stopRecognition() {         mTess.stop();     }      public String getOCRResult(Bitmap bitmap)     {         mTess.setImage(bitmap);         String result = mTess.getUTF8Text();         return result;     }      public void onDestroy()     {         if (mTess != null)             mTess.end();     }      private void copyFile(Context context)     {         AssetManager assetManager = context.getAssets();         try         {   InputStream in = assetManager.open("eng.traineddata");             OutputStream out = new FileOutputStream(datapath + "/tessdata/" + "eng.traineddata");             byte[] buffer = new byte[1024];             int read = in.read(buffer);             while (read != -1) {                 out.write(buffer, 0, read);                 read = in.read(buffer);            }         } catch (Exception e)         {             Log.d("mylog", "couldn't copy with the following error : "+e.toString());         }     } } 

回答1:

If your targetSdkVersion >= 24, then we have to use FileProvider class to give access to the particular file or folder to make them accessible for other apps.

1) First Add a FileProvider tag in AndroidManifest.xml under tag as below:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"     ...     <application         ...         <provider         android:name="android.support.v4.content.FileProvider"         android:authorities="${applicationId}.my.package.name.provider"         android:exported="false"         android:grantUriPermissions="true"         tools:replace="android:authorities">         <meta-data             android:name="android.support.FILE_PROVIDER_PATHS"             android:resource="@xml/provider_paths"             tools:replace="android:resource"/>     </provider>      </application> </manifest> 

2) Then create a provider_paths.xml file in res/xml folder. Folder may be needed to created if it doesn't exist.

<paths>     <external-path name="external_files" path="."/> </paths> 

3) Now edit your activity class file as below:

Uri outputFileUri = Uri.fromFile(newfile); 

to

Uri outputFileUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID, newfile); 

UPDATE #1

Update your MainActivity.java with this:

import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Environment; 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.IOException; import java.util.ArrayList; import java.util.List;  public class MainActivity extends AppCompatActivity {  //    private MyTessOCR mTessOCR = new MyTessOCR(MainActivity.this);      private Button takePictureButton;     private ImageView imageView;          int TAKE_PHOTO_CODE = 0;     public static int count = 0;       @Override     protected void onCreate(Bundle savedInstanceState)     {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         if (checkPermissions()){             //  permissions  granted.          }          final String dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/picFolder/";         File newdir = new File(dir);         if (!newdir.exists()) {             newdir.mkdir();         }          Button capture = (Button) findViewById(R.id.btnCapture);         capture.setOnClickListener(new View.OnClickListener() {             public void onClick(View v) {                  // Here, the counter will be incremented each time, and the                 // picture taken by camera will be stored as 1.jpg,2.jpg                 // and likewise.                 count++;                 String file = dir+count+".jpg";                 File newfile = new File(file);                 try {                     newfile.createNewFile();                 }                 catch (IOException e)                 {                 }                  //     Uri outputFileUri = Uri.fromFile(newfile);                 Uri outputFileUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID, newfile);                  Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);                 cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);                  startActivityForResult(cameraIntent, TAKE_PHOTO_CODE);             }         });       }      @Override     protected void onActivityResult(int requestCode, int resultCode, Intent data)     {         super.onActivityResult(requestCode, resultCode, data);          if (requestCode == TAKE_PHOTO_CODE && resultCode == RESULT_OK) {             Log.d("CameraDemo", "Pic saved");         }     }          public static final int MULTIPLE_PERMISSIONS = 10; // code you want.      String[] permissions= new String[]{             Manifest.permission.WRITE_EXTERNAL_STORAGE,             Manifest.permission.CAMERA,             Manifest.permission.ACCESS_COARSE_LOCATION,             Manifest.permission.ACCESS_FINE_LOCATION};         private  boolean checkPermissions() {         int result;         List<String> listPermissionsNeeded = new ArrayList<>();         for (String p:permissions) {             result = ContextCompat.checkSelfPermission(MainActivity.this,p);             if (result != PackageManager.PERMISSION_GRANTED) {                 listPermissionsNeeded.add(p);             }         }         if (!listPermissionsNeeded.isEmpty()) {             ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),MULTIPLE_PERMISSIONS );             return false;         }         return true;     }       @Override     public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {         switch (requestCode) {             case MULTIPLE_PERMISSIONS:{                 if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){                     // permissions granted.                 } else { //                    Toast.makeText(this, "Go to settings and enable permissions", Toast.LENGTH_LONG) //                            .show();                     }                     // permissions list of don't granted permission                 }                 return;             }         }        private void doOCR()     {         //   String temp = mTessOCR.getOCRResult(bitmap);      } } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!