安卓原生共享到微信、朋友圈,适配Android12
前语
最近作业比较忙,还被人甩了,又逢五一放假,良久没写博客了,okhttp3系列的内容还没写完呢,仍是得打起劲来。这篇博客是最近解决的一个问题,挺有意思,记录下吧!
需求
最近有个APP要上架Google,可是国内的一些SDK无法运用,去除了之后一直在忙适配问题,这儿便是微信SDK不能运用了,导致里边的微信共享都要找替代办法,我这是用的原生自带的。
ps. 202305更新,微博和QQ的SDK也不能上架Google,所以也只能运用体系自带的了,代码已更新。
下面先说下代码,再来讲碰到的各种问题,以及解决办法。
代码
其实代码很简略,便是调用隐式的intent去拜访其他app的页面,传递数据曩昔,我也是拿网上他人的改了改,下面详细说。
共享到微信
共享到微信老友,我这只是传递文字曩昔了,和调用体系共享没什么差异,只是加了包名和类名的一个限定,至于判别运用是否装置,后面会再讲下其中的问题。
/**
* 共享到微信老友
*/
public fun shareTextToWeChat(context: Context, text: String) {
//判别是否装置微信,如果没有装置微信 又没有判别就直达微信共享是会挂掉的
if (!isAppInstall(context, "com.tencent.mm")) {
ToastUtils.show(context, "您还没有装置微信")
return
}
shareText(context, text, "com.tencent.mm", "com.tencent.mm.ui.tools.ShareImgUI")
}
fun shareText(context: Context, text: String, pkg: String, cls: String) {
if (TextUtils.isEmpty(text)) {
ToastUtils.show(context, "内容不能为空")
return
}
try {
val intent = Intent()
intent.component = ComponentName(pkg, cls)
intent.action = Intent.ACTION_SEND
intent.putExtra(Intent.EXTRA_TEXT, text)
intent.type = "text/plain"
context.startActivity(Intent.createChooser(intent, "共享"))
}catch (e: Exception) {
e.printStackTrace()
ToastUtils.show(context, "共享失利")
}
}
fun isAppInstall(context: Context, appPackageName: String): Boolean {
val packageManager = context.packageManager // 获取packagemanager
val info = packageManager.getInstalledPackages(0) // 获取一切已装置程序的包信息
for (i in info.indices) {
val pn = info[i].packageName
if (appPackageName == pn) {
return true
}
}
return false
}
共享到微信朋友圈
共享到朋友圈复杂一点,这儿需求带一张图曩昔,否则就提示获取资源失利,再一个便是文字需求放在“Kdescription”里边。这儿的图片需求一个Uri,这个有点费事,下面再讲。
/**
* 共享到微信朋友圈,需求带一张图
*/
public fun shareTextToWeChatFriend(context: Context, message: WechatUtil.Message) {
if (!isAppInstall(context, "com.tencent.mm")) {
ToastUtils.show(context, "您还没有装置微信")
return
}
try {
val intent = Intent()
intent.component = ComponentName("com.tencent.mm", "com.tencent.mm.ui.tools.ShareToTimeLineUI")
intent.action = Intent.ACTION_SEND
intent.type = "image/*";
val shareStr = """
${message.title}
${message.description}
${message.shareUrl}
""".trimIndent()
intent.putExtra(Intent.EXTRA_TEXT, shareStr)
intent.putExtra("Kdescription", shareStr);
// 给方针运用一个暂时授权,如同用不到
// intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.putExtra(Intent.EXTRA_STREAM, message.thumbnail);
context.startActivity(Intent.createChooser(intent, "共享"))
}catch (e: Exception) {
e.printStackTrace()
ToastUtils.show(context, "共享失利")
}
}
data class Message(
var title: String = "",
var description: String = "",
var shareUrl: String = "",
var scene: String = "",
var thumbnail: Uri? = null)
共享到微博
这儿说几句,网上搜到的文章里边都是”com.sina.weibo.EditActivity”这个包名,经过检测,我发现是错的,最后仍是靠chatGPT才找到对的共享页面包名。
fun shareToWeibo(context: Context, message: ShareUtil.Message) {
if (!isAppInstall(context, "com.sina.weibo")) {
ToastUtils.show(context, "weibo is not install")
return
}
try {
val intent = Intent()
intent.component = ComponentName("com.sina.weibo", "com.sina.weibo.composerinde.ComposerDispatchActivity")
intent.action = Intent.ACTION_SEND
intent.type = "image/*";
val shareStr = """
${message.title}
${message.description}
${message.shareUrl}
""".trimIndent()
intent.putExtra(Intent.EXTRA_TEXT, shareStr)
intent.putExtra(Intent.EXTRA_STREAM, message.thumbnail);
context.startActivity(Intent.createChooser(intent, "共享"))
}catch (e: Exception) {
e.printStackTrace()
ToastUtils.show(context, "共享失利")
}
}
fun shareToWeibo(context: Context, text: String) {
if (!isAppInstall(context, "com.sina.weibo")) {
ToastUtils.show(context, "weibo is not install")
return
}
shareText(context, text, "com.sina.weibo", "com.sina.weibo.composerinde.ComposerDispatchActivity")
}
共享到QQ
这儿有个问题,QQ里边的QQ空间如同不能运用,略微有点坑。共享QQ的代码我试了能够,下面哪个QQ空间的我没装置,不知道行不行。
fun shareToQQ(context: Context, text: String) {
if (!isAppInstall(context, "com.tencent.mobileqq")) {
ToastUtils.show(context, "您还没有装置QQ")
return
}
shareText(context, text, "com.tencent.mobileqq", "com.tencent.mobileqq.activity.JumpActivity")
}
fun shareToQzone(context: Context, text: String) {
if (!isAppInstall(context, "com.qzone")) {
ToastUtils.show(context, "您还没有装置QQ空间")
return
}
shareText(context, text, "com.qzone", "com.qzonex.module.operation.ui.QZonePublishMoodActivity")
}
问题
无法检测是否装置运用
由于要上架Google,我这把targetSdkVersion调到了31(android12),结果一开始便是微信未装置、微博也未装置,有点坑。下面看解决办法:
-
首先在manifest中添加queries标签
<manifest> <application>...</application> <queries> <package android:name="com.tencent.mm" /> <package android:name="com.tencent.mobileqq" /> <package android:name="com.sina.weibo" /> <package android:name="com.qzone" /> </queries> </manifest>
说到这个,我找了良久都没看到queries应该放在哪个方位,去问chatGPT,竟然不苟言笑告诉我放在application里边,太坑了。
-
提高gradle及插件版别
运用了queries后,或许Android studio还不能辨认,找了半天后发现是gradle插件要4.0.1才干支撑,同时gradle的版别也要关于晋级到6.1.1.
-
处理gradle晋级后的问题
我这晋级gradle版别后出了挺多问题,什么不能在manifest里边写minSdkVersion,项目里不能有任何androidx字样,最坑的是gradle里边的minSdkVersion竟然不能用变量设置:
// 错误 defaultConfig.minSdkVersion config.minSdkVersion // 正确 defaultConfig.minSdkVersion 19
我这儿还有一个旧版别的butterknife由于这个用不了了,好在代码不过直接去掉了,其他的看读者自己解决吧。
共享到朋友圈失利
上面现已说到过了共享到朋友圈要带一张图片,文字要经过”Kdescription”去共享,可是这儿还有一个问题,便是Uri的问题。在微信共享SDK中是直接传递bitmap曩昔的(thumbnail),可是我们要传递图片,在Android12就得适配了。
一开始我也觉得直接用拍照的方法供给Uri,7.0以下从文件取得,7.0以上用FileProvider,可是如同不太行:
Uri data;
if (Build.VERSION.SDK_INT >= 24) {
data = FileProvider.getUriForFile(this, PhoneUtils.getAppProcessName(this) + ".opener.provider", cameraFile);
// 给方针运用一个暂时授权
cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
data = Uri.fromFile(cameraFile);
}
由于贮存适配我这儿图片放到了外部私有目录,仍是在沙盒里边,没办法只得写到公有目录去,好在我之前写了个博客Android 不请求权限贮存、删去相册图片,下面就简略改了改,把文件写到相册去了:
import android.content.ContentValues
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.InputStream
object BitmapFileUtil {
// 保存到外部贮存-公有目录-Picture内,而且无需贮存权限
public fun insert2Pictures(context: Context, bitmap: Bitmap): Uri {
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val bais = ByteArrayInputStream(baos.toByteArray())
return insert2Album(context, bais, "Media")
}
// 运用MediaStore方法将流写入相册
@Suppress("SameParameterValue")
private fun insert2Album(context: Context, inputStream: InputStream, type: String): Uri {
val fileName = "${type}_${System.currentTimeMillis()}.jpg"
val contentValues = ContentValues()
contentValues.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, fileName)
// Android 10,路径保存在RELATIVE_PATH
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//RELATIVE_PATH 字段表示相对路径,Fundark为相册下专有目录
contentValues.put(
MediaStore.Images.ImageColumns.RELATIVE_PATH,
Environment.DIRECTORY_PICTURES + File.separator + "YOUR_PATH"
)
} else {
val dstPath = StringBuilder().let { sb->
sb.append(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!.path)
sb.append(File.separator)
sb.append("YOUR_PATH")
sb.append(File.separator)
sb.append(fileName)
sb.toString()
}
//DATA字段在Android 10.0 之后现已废弃(Android 11又启用了,可是只读)
contentValues.put(MediaStore.Images.ImageColumns.DATA, dstPath)
}
// 刺进相册
val uri = context.contentResolver
.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
// 写入文件
uri?.let {
write2File(context, it, inputStream)
}
return uri!!
}
private fun write2File(context: Context, uri: Uri, inputStream: InputStream) {
// 从Uri结构输出流
context.contentResolver.openOutputStream(uri)?.use { outputStream->
val byteArray = ByteArray(1024)
var len: Int
do {
//从输入流里读取数据
len = inputStream.read(byteArray)
if (len != -1) {
outputStream.write(byteArray, 0, len)
outputStream.flush()
}
} while (len != -1)
}
}
}
这儿把你的bitmap传进去,就能拿到Uri了,不过这儿的名字我是随机命名的,有需求能够传递进去,用这个Uri就能把图片传递到微信了,不过要注意上面这些是IO操作,最好发动个线程履行。
结语
大致内容便是这样了,我这微信老友和微信朋友圈都能共享曩昔,撒花!下面贴一张chatGPT胡言乱语的图: