through studio item intent geturi getdata fileuriexposedexception exposed error clipdata beyond app android image camera onclick media

android - studio - exposed beyond app through clipdata.item.geturi() camera



android.os.FileUriExposedException: file.jpg expuesto más allá de la aplicación a través de ClipData.Item.getUri() (2)

Intento hacer un botón que abra la cámara y tome una foto. mi código está aquí

//for imports check on bottom of this code block public class HomeProfileActivity extends AppCompatActivity { //Button camera public static final String TAG = HomeProfileActivity.class.getSimpleName(); public static final int REQUEST_TAKE_PHOTO = 0; public static final int REQUEST_TAKE_VIDEO = 1; public static final int REQUEST_PICK_PHOTO = 2; public static final int REQUEST_PICK_VIDEO = 3; public static final int MEDIA_TYPE_IMAGE = 4; public static final int MEDIA_TYPE_VIDEO = 5; private Uri mMediaUri; private ImageView photobutton; private Button buttonUploadImage, buttonTakeImage; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home_profile); ButterKnife.bind(this); } @OnClick(R.id.buttonTakeImage) void takePhoto() { mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); if (mMediaUri == null) { Toast.makeText(this, "There was a problem accessing your device''s external storage.", Toast.LENGTH_LONG).show(); } else { Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri); startActivityForResult(takePhotoIntent, REQUEST_TAKE_PHOTO); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK){ if (requestCode == REQUEST_TAKE_PHOTO) { Intent intent = new Intent(this, ViewImageActivity.class); intent.setData(mMediaUri); startActivity(intent); } } else if (resultCode != RESULT_CANCELED){ Toast.makeText(this, "Sorry, there was an error", Toast.LENGTH_SHORT).show(); } } private Uri getOutputMediaFileUri(int mediaType) { // check for external storage if (isExternalStorageAvailable()) { // get the URI // 1. Get the external storage directory File mediaStorageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); // 2. Create a unique file name String fileName = ""; String fileType = ""; String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); if (mediaType == MEDIA_TYPE_IMAGE) { fileName = "IMG_" + timeStamp; fileType = ".jpg"; } else if (mediaType == MEDIA_TYPE_VIDEO) { fileName = "VID_" + timeStamp; fileType = ".mp4"; } else { return null; } // 3. Create the file File mediaFile; try { mediaFile = File.createTempFile(fileName, fileType, mediaStorageDir); Log.i(TAG, "File: " + Uri.fromFile(mediaFile)); // 4. Return the file''s URI return Uri.fromFile(mediaFile); } catch (IOException e) { Log.e(TAG, "Error creating file: " + mediaStorageDir.getAbsolutePath() + fileName + fileType); } } // something went wrong return null; } private boolean isExternalStorageAvailable(){ String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)){ return true; } else { return false; } } import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.design.widget.BottomNavigationView; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import butterknife.ButterKnife; import butterknife.OnClick;

También tengo un problema con startActivityForResult en el método onclick y la importación java.text.SimpleDateFormat; También saltar en el tiempo de ejecución de excepción estoy trabajando con buildtoolsversion sdk 25


Además de la solución que utiliza FileProvider, hay otra forma de solucionar esto. Simplemente pon

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

en el método Application.onCreate (). De esta manera, la máquina virtual ignora la exposición del archivo URI.


Esta información es de: FileUriExposedException

Esto solo se lanza para aplicaciones dirigidas a N o superior. Las aplicaciones que apuntan a versiones anteriores del SDK pueden compartir el archivo: // Uri, pero no se recomienda.

Por lo tanto, si compileSdkVersion (objetivo de compilación) del archivo app/build.gradle es Android N (API nivel 24) o superior, se compileSdkVersion este error si escribe un archivo al que posiblemente otras aplicaciones puedan acceder. Lo más importante, aquí es cómo se supone que debes hacerlo al avanzar:

tomado de aquí: FileProvider

Cambio:

return Uri.fromFile(mediaFile);

ser

return FileProvider.getUriForFile(getApplicationContext(), getPackageName()+".fileprovider", mediaFile);

Nota: si controla mydomain.com , también puede reemplazar getPackageName()+".fileprovider" por "com.mydomain.fileprovider" (lo mismo ocurre con su AndroidManifest.xml continuación.

También debe agregar lo siguiente a su archivo AndroidManifest.xml justo antes de su etiqueta </application>

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

Luego, debe agregar un archivo llamado filepaths.xml a su directorio app/src/main/res/xml con el siguiente contenido

<paths> <external-files-path name="Pictures" path="Pictures" /> </paths>

Nota: para cualquier otra persona, usamos external-files-path arriba, ya que Omer usó getExternalFilesDir(Environment.DIRECTORY_PICTURES) en el código. Para cualquier otra ubicación, marque FileProvider en la sección "Especificación de archivos disponibles" y cambie external-files-path a una de las siguientes según la ubicación de sus archivos:

files-path cache-path external-path external-files-path external-cache-path

Además, revisa las Pictures arriba para que sean el nombre de tu carpeta.

Un antipatrón importante a evitar es que NO debe usar if (Build.VERSION.SDK_INT < 24) { para permitirle hacerlo de la manera anterior, ya que no es su versión de Android la que requiere esto, es su versión de compilación (I perdí esto la primera vez que lo codifiqué).

Sé que esto es más trabajo, sin embargo, esto permite que Android permita solo el acceso temporal al archivo a la otra aplicación con la que está compartiendo, lo que es más seguro para la privacidad del usuario.