Android: Как написать намерение камеры в Android Nougat

В моем приложении для Android я должен делать снимки с помощью камеры по нажатию кнопки. Он отлично работает во всех версиях Android, кроме Android 7 (Nougat). Когда я нажимаю опцию камеры, приложение закрывается, даже если разрешения включены. Я думаю, что Проблема в намерении камеры. Ниже приведен мой код.

    camera = (ImageView) dialog.findViewById(R.id.camera);

camera.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        clickCamera();
        dialog.dismiss();
    }
});

private void clickCamera() { // 1 for icon and 2 for attachment
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CAMERA},MY_REQUEST_CODE);
    }else {
        if (ActivityCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_REQUEST_CODE_STORAGE);
        }else{
            currentImageUri = getImageFileUri();
            Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            intentPicture.putExtra(MediaStore.EXTRA_OUTPUT, currentImageUri); // set the image file name
            // start the image capture Intent
            startActivityForResult(intentPicture, REQUEST_CAMERA);  // 1 for REQUEST_CAMERA and 2 for REQUEST_CAMERA_ATT
        }
    }
}

private static Uri getImageFileUri(){
    // Create a storage directory for the images
    // To be safe(er), you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this

    imagePath = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyProject");
    if (! imagePath.exists()){
        if (! imagePath.mkdirs()){
            return null;
        }else{
            //create new folder
        }
    }

    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File image = new File(imagePath,"MyProject_"+ timeStamp + ".jpg");

    if(!image.exists()){
        try {
            image.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // Create an File Uri
    return Uri.fromFile(image);
}


@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_REQUEST_CODE: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // permission was granted, yay! Do the
            // contacts-related task you need to do.
                if (ActivityCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_REQUEST_CODE_STORAGE);
                }else{
                    currentImageUri = getImageFileUri();
                    Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    intentPicture.putExtra(MediaStore.EXTRA_OUTPUT, currentImageUri); // set the image file name
                    // start the image capture Intent
                    startActivityForResult(intentPicture, REQUEST_CAMERA);
                }
            } else {
                // permission denied, boo! Disable the
                // functionality that depends on this permission.
                Toast.makeText(this,"Doesn't have permission... ", Toast.LENGTH_SHORT).show();
            }
            return;
        }
        case MY_REQUEST_CODE_STORAGE : {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                currentImageUri = getImageFileUri();
                Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intentPicture.putExtra(MediaStore.EXTRA_OUTPUT, currentImageUri); // set the image file name
                // start the image capture Intent
                startActivityForResult(intentPicture, REQUEST_CAMERA);
            } else {
                // permission denied, boo! Disable the
                // functionality that depends on this permission.
                Toast.makeText(this,"Doesn't have permission...", Toast.LENGTH_SHORT).show();
            }
            return;
        }
    }
}

В чем здесь проблема для Nougat. Это из-за uri, возвращенного getImageFileUri()?? Пожалуйста, помогите мне решить это.

5 ответов

Решение

Эй, пожалуйста, следуйте этой теме в качестве ссылки. Он покажет вам, как использовать File Provider, когда вы установите для targetSDK значение 24 и измените следующий. В вашем private static Uri getImageFileUri() метод

Изменить эту строку

return Uri.fromFile(image);

в

FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", createImageFile());

Надеюсь, что это поможет вам решить вашу проблему.
Для получения дополнительной информации перейдите к - Настройка общего доступа к файлам - Официальная документация

Попробуйте, это не намерение, которое создает проблему, как только вы делаете снимок и сохраняете его на SD-карту, и возвращение URI отличается в Nougat....

Это довольно легко реализовать FileProvider в вашем приложении. Сначала вам нужно добавить тег FileProvider в AndroidManifest.xml под тегом, как показано ниже: AndroidManifest.xml

<?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}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>
    </application>
</manifest>

А затем создайте файл provider_paths.xml в папке xml в папке res. Папка может быть необходима для создания, если она не существует.

Рез / XML /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>

Готово! FileProvider теперь объявлен и готов к использованию.

Последний шаг - изменить строку кода ниже в MainActivity.java.

Uri photoURI = Uri.fromFile(createImageFile());

в

Uri photoURI = FileProvider.getUriForFile(MainActivity.this,
            BuildConfig.APPLICATION_ID + ".provider",
            createImageFile());

И.... готово! Ваше приложение теперь должно прекрасно работать на любой версии Android, включая Android Nougat. Ура!

Что ж, задача Android - превращать жизнь разработчиков в ад с каждым обновлением:)

googlers, вот пошаговое руководство для разработчиков, которые (как и вопрос) использовали примеры в документации Android;

1- в той части, которую вы использовали

Uri.fromFile(image)

вам нужно использовать этот фрагмент:

Uri photoURI = FileProvider.getUriForFile(mContext,
                        "com.sample.test.fileprovider",
                        image);

конечно, само собой разумеется, что вы должны изменить com.sample.test на имя вашего пакета.

2 - теперь вам нужно объявить вашего провайдера в вашем AndroidManifest.xml, чтобы сделать это, в теге приложения вставьте этот тег:

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.sample.test.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />

3- обратите внимание на android:resource="@xml/file_paths" вам нужно создать XML-файл с тем же именем file_paths под вашим res/xml/ папку и поместите это в нее:

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

на пару других фрагментов в Интернете, и сама документация, он говорит, что вам нужно написать это

<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />

вместо нашего, это на самом деле зависит от вашего кода, если вы создаете свой файл с помощью Environment.getExternalStorageDirectory().getPath() вам это не нужно, но если вы следовали в точности как документы, вам нужно придерживаться документов

Здесь исправлена ​​проблема с намерением камеры в версии 7.0,

file: // больше не разрешено (Android N) присоединять с помощью Intent, иначе будет выдано исключение FileUriExposedException, которое может вызвать немедленный вызов приложения.

Пожалуйста, проверьте все детали проблем и их решение.

Soltution

Используйте File Provider, это поможет вам

Другие вопросы по тегам