Share file Kotlin

Как поделиться любым файлом в Kotlin?

Оказывается, начиная с версии targetSdkVersion 24 и выше недостаточно просто написать функцию Share file, а нужно еще настроить provider в файле AndroidManifest.xml. Если вы этого не сделаете то при попытке поделиться например в WhatsApp, Telegram или Email вы получите ошибку “intent Share File.type unsupported attachment PID:…“. Эта ошибка говорит, что ваш вложенный файл не поддерживается.

Что нужно сделать, чтобы всё работало как надо?

1. Добавим разрешение на чтение и запись фалов

Разрешения записываем разумеется в файле AndroidManifest.xml. Тут сразу есть нюанс:

До Android 10 используется разрешение:
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>

Начиная с Android 10 и выше:
<uses-permission android:name=”android.permission.MANAGE_EXTERNAL_STORAGE” tools:ignore=”ScopedStorage” />

Ну и конечно просто написать разрешения в файле AndroidManifest.xml это было бы слишком просто, их нужно еще запросить, когда приложение запустится, для этого напишем следующую функцию:

// ----------------- ПРОВЕРКА НА ЗАПИСЬ В ПАМЯТЬ ------------------------------------------------

    // 1. Разрешение на ЧТЕНИЕ и ЗАПИСЬ ФАЙЛОВ
    fun hasManageExternalStoragePermission(): Boolean {
        val RESULT_CODE = 123
        // Если Android 11 и выше
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            return if (Environment.isExternalStorageManager()) {
                true
            } else {
                if (Environment.isExternalStorageLegacy()) {
                    return true
                }
                try {
                    val intent = Intent()
                    intent.action = Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
                    intent.data = Uri.parse("package:ru.jandroid.fileencrypt")
                    APP.startActivityForResult(intent, RESULT_CODE)
                    false
                } catch (e: Exception) {
                    Toast.makeText(APP, "Разрешение отклонено", Toast.LENGTH_SHORT).show()
                    false
                }
            }
        }
        // Если Android ниже 10
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
            // 2.
            registerPermissionListener()
            return checkWritePermissions()
        } else
            return true
    }

    // 2. Получить разрешение на ЗАПИСЬ (Android < R)
    fun  checkWritePermissions(): Boolean {
        when{
            ContextCompat.checkSelfPermission(APP, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED -> {
                //Toast.makeText(APP, "Разрешение было получено ранее", Toast.LENGTH_SHORT).show()
                return true
            }
            else -> {
                permisLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                return false
            }
        }
    }

    // 2. Слушатель разрешения (Android < R)
    fun  registerPermissionListener(){
        permisLauncher = APP.registerForActivityResult(ActivityResultContracts.RequestPermission()){
            if(it) {
                //Toast.makeText(APP, "Вы дали разрешение для записи.", Toast.LENGTH_SHORT).show()
            }else{
                //Toast.makeText(APP, "Разрешение отклонено", Toast.LENGTH_SHORT).show()
                showDialog()
            }
        }
    }

    // Диалог поясняющий необходимость разрешения и повтор запроса
    fun showDialog() {
        AlertDialog.Builder(APP)
            .setTitle("Разрешение на запись")
            .setMessage("Дайте разрешение на запись. В противном случае приложение работать не будет!")
            .setPositiveButton("Разрешить") { dialog, which ->
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) checkWritePermissions()
                else hasManageExternalStoragePermission()
            }
            .setNegativeButton("Отклонить") { dialog, which ->
                APP.finish()
            }
            .show()
    }

Теперь в MainActivity.kt в методе onCreate вызовите функцию:
hasManageExternalStoragePermission() и добавим слушатель на действие пользователя:

class MainActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
        ...
        hasManageExternalStoragePermission()
        ...

}

// Если версия Android 11 проверяем разрешил ли пользователь запись
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && Environment.isExternalStorageManager()){
        //Доступ к памяти разрешен
    }else {
        //Отказано в доступе, то открываем диалог
        showDialog()
    }
}

Теперь у вас будет разрешение на чтение и запись файлов из внутренней памяти.

2. Напишем Provider

В файле MainActivity.kt нужно написать следующий код:

  <application ...>
   ...   
        <provider
            android:name="androidx.core.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>

И создать файл provider_paths.xml в res/xml . Нижеприведенный код позволит передавать все файлы.

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

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

3. Основная функция Share files

    fun shareFile(file: File){
        val uri = FileProvider.getUriForFile(APP, BuildConfig.APPLICATION_ID + ".provider", file)
        val intent = Intent(Intent.ACTION_SEND)
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        intent.setType("*/*")
        intent.putExtra(Intent.EXTRA_STREAM, uri)
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        APP.startActivity(intent)
    }

Вот такие вот сложности с маленькой функцией Share file (поделится файликом). Но теперь все должно работать.

Поделись с друзьями:
Если вам понравилась статья, подписывайтесь на наши социальные сети.

Оставьте комментарий

6 + 5 =