Android:将带有可播放视频的 Intent 发送到电报应用程序

标签 android android-intent

我想通过 Intent 将视频发送到电报应用程序,但是当我发送它时,它作为文件发送(图像也是如此)。有没有什么技巧可以指定您要如何发送它? (因为它从画廊发送相同的可播放视频)

Intent发送函数

private fun shareItem(fileName: String) {
    Log.i(TAG, "shareItem: ")
    val videoContentUri = FileProvider.getUriForFile(requireContext(),
        "${activity?.applicationContext?.packageName}.provider",
        File(LocalFilesRepository.getFullVideoPath(fileName, requireContext()))
    )
    Log.i("TAG", "shareItem: $videoContentUri")


    val shareIntent: Intent = Intent().apply {
        action = Intent.ACTION_SEND
        flags =  Intent.FLAG_GRANT_READ_URI_PERMISSION
        putExtra(Intent.EXTRA_STREAM, videoContentUri)
        type = "video/mp4"
    }
    startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.send_to)))
}

...
fun getFullVideoPath(fileName: String, context: Context) =
            context.getExternalFilesDir(Environment.DIRECTORY_MOVIES).toString() + File.separatorChar + fileName

videoContentUri 看起来像这样 content://com.dmytroa.appname.provider/external_files/emulated/0/Android/data/com.dmytroa.appname/files/Movies/1625360538459.mp4

最佳答案

如果有人感兴趣,我通过在公共(public)存储中临时保存一个文件然后从 Mediastore 返回 Uri 来解决它。

fun createTemporaryCopyInPublicStorage(file: File, context: Context): Uri? {
            val fileName = "tmp"
            return if(Build.VERSION.SDK_INT >= 29) {
                val uri = findCreatedTemporaryUri(context, fileName, TEMPORARY_DIR_Q)
                copyVideoQAndAbove(context, file, uri, fileName, TEMPORARY_DIR_Q)
            } else {
                val uri = findCreatedTemporaryUri(context, fileName, TEMPORARY_DIR_BELOWQ)
                copyVideoBelowQ(context, file, uri, fileName, TEMPORARY_DIR_BELOWQ)
            }
        }


        private fun findCreatedTemporaryUri(context: Context, fileName: String, path: String): Uri? {
            val collection = if(Build.VERSION.SDK_INT >= 29) {
                MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
            } else {
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI
            }

            val selection = if (Build.VERSION.SDK_INT >= 29) {
                "${MediaStore.Video.Media.TITLE} = ? " +
                        "AND " +
                        "${MediaStore.Video.Media.RELATIVE_PATH} = ? "
            } else {
                "${MediaStore.Video.Media.TITLE} = ? " +
                        "AND " +
                        "${MediaStore.Video.Media.DATA} = ? "
            }

            val args = if (Build.VERSION.SDK_INT >= 29) {
                arrayOf(fileName, path)
            } else {
                arrayOf(fileName, File(path, fileName).absolutePath)
            }

            context.contentResolver.query(
                collection,
                arrayOf(MediaStore.Video.Media._ID
                ),
                selection,
                args,
                null
            ).use { cursor ->
                return if (cursor != null && cursor.moveToFirst()) {
                    val columnIndexID = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
                    val id = cursor.getLong(columnIndexID)

                    Log.i(TAG, "findCreatedTemporaryUri: " +
                            "contentUri was already added $id $path $fileName")
                    Uri.withAppendedPath(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "$id")
                } else {
                    null
                }
            }
        }

        @RequiresApi(Build.VERSION_CODES.Q)
        private fun copyVideoQAndAbove(context: Context,
                                       fileToCopy: File,
                                       uri: Uri?,
                                       fileName: String,
                                       relPath: String): Uri? {

            val contentDetails = ContentValues().apply {
                put(MediaStore.Video.Media.IS_PENDING, 1)
            }

            val contentUri = if (uri != null) {
                context.contentResolver.update(uri, contentDetails, null, null)
                uri
            } else {
                Log.i(TAG, "saveVideoQAndAbove: contentUri insert")
                contentDetails.apply {
                    put(MediaStore.Video.Media.DISPLAY_NAME, fileName)
                    put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
                    put(MediaStore.Video.Media.RELATIVE_PATH, relPath)
                }
                val collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
                context.contentResolver.insert(collection, contentDetails)
            }

            return contentUri?.let { createdUri ->
                try {
                    context.contentResolver.openFileDescriptor(createdUri, "w").use { pfd ->
                        ParcelFileDescriptor.AutoCloseOutputStream(pfd).write(fileToCopy.readBytes())
                    }
                } catch (e: IOException) {
                    e.printStackTrace()
                }

                contentDetails.clear()
                contentDetails.put(MediaStore.Video.Media.IS_PENDING, 0)
                context.contentResolver.update(createdUri, contentDetails, null, null)
                createdUri
            }
        }

        private fun copyVideoBelowQ(context: Context,
                                    fileToCopy: File,
                                    uri: Uri?,
                                    fileName: String,
                                    dstParentPath: String): Uri? {
            val dstDir = File(dstParentPath)
            if (!dstDir.exists())
                dstDir.mkdirs()

            val fileToCreate = File(dstDir, fileName)

            fileToCreate.delete()
            fileToCreate.createNewFile()
            Log.i(TAG, "saveVideo: created ${fileToCreate.name}")
            try {
                fileToCopy.inputStream().use { input ->
                    fileToCreate.outputStream().use { output ->
                        input.copyTo(output, 2 * 1024)
                        Log.i(TAG, "saveVideo: finished ${fileToCreate.path}")
                    }
                }
                return uri ?: let {
                    val values = ContentValues().apply {
                        put(MediaStore.Video.Media.TITLE, fileToCreate.name)
                        put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
                        put(MediaStore.Video.Media.DATA, fileToCreate.path)
                    }
                    context.contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values)
                }
            } catch (e: IOException) {
                e.printStackTrace()
            }

            return null
        }

        private val TEMPORARY_DIR_Q = Environment.DIRECTORY_MOVIES + File.separator +
                "APPNAME" + File.separator +
                "temporary" + File.separator

        private val TEMPORARY_DIR_BELOWQ = Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_MOVIES).absolutePath + File.separator +
                "APPNAME" + File.separator +
                "temporary" + File.separator

关于Android:将带有可播放视频的 Intent 发送到电报应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68241799/

相关文章:

android - Google Play 中的 AWS 安全警报

android - 在另一个 Activity 中使用在一个 Activity 中获取的数据

android - 无线设置对话框

java - OKHttp句柄302

android - 以编程方式将项目添加到 ScrollView 顶部,但不应滚动到顶部

android - 使用 SectionsPagerAdapter android

android - 使用 Phonegap 发送短信并显示在收件箱中

android - queryIntentActivities() 在结果中包含私有(private) Activity

android - android : 'Failed to find style with id 0x7fff0062 in current theme 中的 cardView 错误

Android Studio 在红线中提示 "Cannot access androidx.activity.ComponentActivity"但编译正常