IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 系统分享框分享文件 -> 正文阅读

[移动开发]Android 系统分享框分享文件

Build.VERSION.SDK_INT >= Build.VERSION_CODES.N声明文件传输权限
AndroidManifest.xml声明权限provider统一格式

<provider
    android:name="androidx.core.content.FileProvider"
    <!--一般包名加.FileProvider(可以随便定义)-->
    android:authorities="com.dev.apkshare.FileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>


res下创建xml目录后创建file_paths.xml配置文件

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <!--Android/data/包名/-->
    <external-path path="Android/data/com.dev.apkshare(包名)/" name="files_root" />
    <external-path path="." name="external_storage_root" />
    <external-path name="external_files" path="."/>
    <external-path name="storage" path="storage/"/>
    <files-path name="tangdada" path="download/" />
    <root-path path="" name="." />
</paths>

 ShareUtils.kt


object ShareUtils {
    fun share(activity: Activity, path: String) {
        val sourceDir = File(path)
        val mimetype = ShareSystem.ShareContentType.FILE
        //文件存在
        if (sourceDir.exists()) {
            //版本大于23
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //uri转换
                val uri = FileProvider.getUriForFile(activity,
                        activity.packageName + ".FileProvider", sourceDir)
                ShareSystem.Builder(activity).setContentType(mimetype)
                        .setShareFileUri(uri)
                        .forcedUseSystemChooser(false)
                        .build()
                        .shareBySystem()
            } else {
                val intent = Intent(Intent.ACTION_VIEW)
                intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                intent.setDataAndType(Uri.fromFile(sourceDir), mimetype)
                activity.startActivity(Intent.createChooser(intent, "分享"))
            }
        } else {
            Toast.makeText(activity, "$path 文件不存在", Toast.LENGTH_LONG).show()
        }
    }
}

创建拉起分享界面intent

class ShareSystem private constructor(builder: Builder) {

    val TAG = javaClass.simpleName

    /**
     * 当前 activity
     */
    private val activity: Activity?

    /**
     * 分享格式
     */
    @ShareContentType
    private val contentType: String

    /**
     * 分享标题
     */
    private var title: String? = null

    /**
     * 分销uri
     */
    private val shareFileUri: Uri?

    /**
     * 分享内容
     */
    private val contentText: String?


    private val componentPackageName: String?


    private val componentClassName: String?


    private val requestCode: Int


    private val forcedUseSystemChooser: Boolean

    init {
        this.activity = builder.activity
        this.contentType = builder.contentType
        this.title = builder.title
        this.shareFileUri = builder.shareFileUri
        this.contentText = builder.textContent
        this.componentPackageName = builder.componentPackageName
        this.componentClassName = builder.componentClassName
        this.requestCode = builder.requestCode
        this.forcedUseSystemChooser = builder.forcedUseSystemChooser
    }

    /**
     * shareBySystem
     */
    fun shareBySystem() {
        if (checkShareParam()) {
            var shareIntent = createShareIntent()

            if (shareIntent == null) {
                Log.e(TAG, "shareBySystem cancel.")
                return
            }

            if (title == null) {
                title = ""
            }

            if (forcedUseSystemChooser) {
                shareIntent = Intent.createChooser(shareIntent, title)
            }

            if (shareIntent!!.resolveActivity(activity!!.packageManager) != null) {
                try {
                    if (requestCode != -1) {
                        activity.startActivityForResult(shareIntent, requestCode)
                    } else {
                        activity.startActivity(shareIntent)
                    }
                } catch (e: Exception) {
                    Log.e(TAG, Log.getStackTraceString(e))
                }

            }
        }
    }

    private fun createShareIntent(): Intent? {
        var shareIntent: Intent? = Intent()
        shareIntent!!.action = Intent.ACTION_SEND
        shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        shareIntent.addCategory("android.intent.category.DEFAULT")

        if (!TextUtils.isEmpty(this.componentPackageName) && !TextUtils.isEmpty(componentClassName)) {
            val comp = ComponentName(componentPackageName!!, componentClassName!!)
            shareIntent.component = comp
        }

        when (contentType) {
            ShareContentType.TEXT -> {
                shareIntent.putExtra(Intent.EXTRA_TEXT, contentText)
                shareIntent.type = "text/plain"
            }
            ShareContentType.IMAGE, ShareContentType.AUDIO, ShareContentType.VIDEO, ShareContentType.FILE -> {
                shareIntent.action = Intent.ACTION_SEND
                shareIntent.addCategory("android.intent.category.DEFAULT")
                shareIntent.type = contentType
                shareIntent.putExtra(Intent.EXTRA_STREAM, shareFileUri)
                shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                Log.d(TAG, "Share uri: " + shareFileUri!!.toString()+" VERSION = "+Build.VERSION.SDK_INT+" forcedUseSystemChooser = "+forcedUseSystemChooser)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    val resInfoList = activity!!.packageManager.queryIntentActivities(shareIntent, PackageManager.MATCH_DEFAULT_ONLY)
                    for (resolveInfo in resInfoList) {
                        val packageName = resolveInfo.activityInfo.packageName
                        //赋予临时权限
                        activity.grantUriPermission(packageName, shareFileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
                    }
                }
            }
            else -> {
                Log.e(TAG, "$contentType is not support share type.")
                shareIntent = null
            }
        }

        return shareIntent
    }

    private fun checkShareParam(): Boolean {
        if (this.activity == null) {
            Log.e(TAG, "activity is null.")
            return false
        }

        if (TextUtils.isEmpty(this.contentType)) {
            Log.e(TAG, "Share content type is empty.")
            return false
        }

        if (ShareContentType.TEXT == contentType) {
            if (TextUtils.isEmpty(contentText)) {
                Log.e(TAG, "Share text context is empty.")
                return false
            }
        } else {
            if (this.shareFileUri == null) {
                Log.e(TAG, "Share file path is null.")
                return false
            }
        }

        return true
    }

    class Builder(val activity: Activity) {
        @ShareContentType
        var contentType = ShareContentType.FILE
        var title: String? = null
        var componentPackageName: String? = null
        var componentClassName: String? = null
        var shareFileUri: Uri? = null
        var textContent: String? = null
        var requestCode = -1
        var forcedUseSystemChooser = true

        /**
         * Set Content Type
         *
         * @param contentType [ShareContentType]
         * @return Builder
         */
        fun setContentType(@ShareContentType contentType: String): Builder {
            this.contentType = contentType
            return this
        }

        /**
         * Set Title
         *
         * @param title title
         * @return Builder
         */
        fun setTitle(title: String): Builder {
            this.title = title
            return this
        }

        /**
         * Set share file path
         *
         * @param shareFileUri shareFileUri
         * @return Builder
         */
        fun setShareFileUri(shareFileUri: Uri): Builder {
            this.shareFileUri = shareFileUri
            return this
        }

        /**
         * Set text content
         *
         * @param textContent textContent
         * @return Builder
         */
        fun setTextContent(textContent: String): Builder {
            this.textContent = textContent
            return this
        }

        /**
         * Set Share To Component
         *
         * @param componentPackageName componentPackageName
         * @param componentClassName   componentPackageName
         * @return Builder
         */
        fun setShareToComponent(componentPackageName: String, componentClassName: String): Builder {
            this.componentPackageName = componentPackageName
            this.componentClassName = componentClassName
            return this
        }

        /**
         * Set onActivityResult requestCode, default value is -1
         *
         * @param requestCode requestCode
         * @return Builder
         */
        fun setOnActivityResult(requestCode: Int): Builder {
            this.requestCode = requestCode
            return this
        }

        /**
         * Forced Use System Chooser To Share
         *
         * @param enable default is true
         * @return Builder
         */
        fun forcedUseSystemChooser(enable: Boolean): Builder {
            this.forcedUseSystemChooser = enable
            return this
        }

        /**
         * build
         *
         * @return Share2
         */
        fun build(): ShareSystem {
            return ShareSystem(this)
        }

    }

    @Retention(RetentionPolicy.SOURCE)
    annotation class ShareContentType {
        companion object {
            /**
             * Share Text
             */
            val TEXT = "text/plain"

            /**
             * Share Image
             */
            val IMAGE = "image/*"

            /**
             * Share Audio
             */
            val AUDIO = "audio/*"

            /**
             * Share Video
             */
            val VIDEO = "video/*"

            /**
             * Share File
             */
            val FILE = "*/*"
        }
    }
}

注意:

shareIntent = Intent.createChooser(shareIntent, title)

有些会用上面方式拉起系统分享界面,这个会报下面问题导致无法添加各个分享应用

java.lang.SecurityException: Permission Denial: reading androidx.core.content.FileProvider uri content://com.dev.apkshare.FileProvider/./system/priv-app/DocumentsUI_royole/DocumentsUI_royole.apk from pid=17076, uid=1000 requires the provider be exported, or grantUriPermission()
? ? ? ? at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:768)
? ? ? ? at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:641)
? ? ? ? at android.content.ContentProvider$Transport.query(ContentProvider.java:235)
? ? ? ? at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:104)
? ? ? ? at android.os.Binder.execTransactInternal(Binder.java:1021)
? ? ? ? at android.os.Binder.execTransact(Binder.java:994)

解决方法:

直接使用shareIntent不要通过Intent.createChooser创建。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-03 11:19:29  更:2021-08-03 11:21:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 18:47:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码