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创建。
|