小红书分享踩坑和解决

小红书官方介入链接:小红书分享开放平台

下载sdk文件,位置如下图所示

 

之后可以按照官方文档进行开发,接入也较简单,这里主要是说明一些隐藏的坑点

一、分享应用内的文件到小红书(这里主要是指应用包名下的文件内容),需要注意setFileProviderAuthority()这个方法。

例如我的代码如下:

AndroidManifest文件
<provider
 android:name="androidx.core.content.FileProvider"
 android:authorities="${applicationId}.FileProvider"
 android:exported="false"
 android:grantUriPermissions="true"
 >
 <meta-data
 android:name="android.support.FILE_PROVIDER_PATHS"
 android:resource="@xml/provider_paths"
 />
 </provider>
res目录下的xml配置文件
<?xml version="1.0" encoding="utf-8"?>
<paths>
 <cache-path
 name="cache"
 path="."
 /> <!--Context.getCacheDir() -->
 <files-path
 name="files"
 path="."
 /> <!--Context.getFilesDir() -->
 <external-path
 name="external"
 path="."
 /> <!-- Environment.getExternalStorageDirectory()-->
 <external-cache-path
 name="external-cache"
 path="."
 /> <!-- Context.getExternalCacheDir() -->
 <external-files-path
 name="external-files"
 path="."
 /> <!-- Context.getExternalFilesDir() -->
 <external-files-path
 name="opensdk_external"
 path="Images"
 />
 <root-path
 name="opensdk_root"
 path=""
 />
</paths>

像我的项目配置的话,需要设置的代码如下

XhsShareSdk.registerApp(context, XHS_APP_KEY,
 XhsShareGlobalConfig().setEnableLog(true).setClearCacheWhenShareComplete(true)
//重点是下面的这句话,设置为自己应用的 Authority
.setFileProviderAuthority("${context.packageName}.FileProvider")
 ,
 object : XhsShareRegisterCallback {
 override fun onSuccess() {
 log { "xhs---onSuccess: 注册成功!" }
 }
 override fun onError(
 errorCode: Int,
 errorMessage: String,
 @Nullable exception: Exception?
 ) {
 log { "xhs---onError: 注册失败!errorCode: $errorCode errorMessage: $errorMessage exception: $exception" }
 }
 })

二、小红书构造方法的坑:

XhsNote().apply {
 title = getTitleString() // 正文,String
 content = getContentString() // 标题,String
 imageInfo = XhsImageInfo(listOf(
 XhsImageResourceBean.fromUrl("网络图片 url"), 
 XhsImageResourceBean.fromUrl("网络图片 url"))) 
}

小红书的示例代码和说明,都说的很简单,可以直接使用fromUrl这个方法进行构造,他会自动识别是网络图片还是本地图片。不需要手动处理了。

但是,之后,你就会发现,分享网络资源没有问题,但是如果分享的内容是自己应用内部的文件,就无论如何,都分享不成功,到了小红书APP,就提示未获取到图片或者视频。

请看SDK代码

 

小红书SDK里面判断了是否是网络地址,然后通过File的构造方法,调用了顶部的Uri.fromFile(filePath),这个方法是存在问题的。

安卓7.0强制启用了striceMode策略,无法直接暴露file://类型的URI了。如果使用的公共目录分享文件,还是可以成功的,但是如果分享的是应用内部的文件,就会出现没有访问权限的问题。所以小红书APP,就会一直报为获取资源的问题。

解决办法:

使用XhsImageResourceBean(Uri)方式去构造视频和图片的对象。示例代码如下:

fun shareXHS(
 activity: Activity = requireNotNull(SnsHelper.mainActivity),
 filePath: String//传递过来文件地址
 ) {
 val xhsPackageNames = arrayOf("com.xingin.xhs")
 //获取赋予权限的URI
 val uri = getContentUriForFileProvider(
 filePath = filePath,
 packages = xhsPackageNames
 )
 log { "xhs--- FilePath=$filePath \n,uri:$uri, " }
 val title="标题内容"
 val content="内容文字"
 try {
 //获取视频的首帧作为封面图
 val bitmap= getThumbnailFromVideo(filePath)
 val tempFile = File("${activity.cacheDir.absolutePath}/cameraShooting", "tempFileForShare.png")
 val stream = FileOutputStream(tempFile)
 bitmap?.compress(Bitmap.CompressFormat.PNG, 100, stream)
 stream.close()
 //获取首帧的图片URI
 val picUri = getContentUriForFileProvider(
 filePath = tempFile.absolutePath,
 packages = xhsPackageNames
 )
 val xhsNote= XhsNote().apply {
 this.title = title
 this.content = content
 videoInfo = XhsVideoInfo(
 //通过URI的方式,构建数据
 XhsVideoResourceBean(uri),
 XhsImageResourceBean(picUri)
 ) // 封面
 }
 //分享数据
 val sessionId = XhsShareSdk.shareNote(activity, xhsNote)
 }catch (e:Exception){ }
 }
 fun getContentUriForFileProvider(
 filePath: String,
 packages: Array<String> = emptyArray(),
 context: Context = CoreApp.getContext(),
 ): Uri {
 //根据文件路径,生成关联的 content:// 内容 URI 
 val file = File(filePath)
 val contentUri = FileProvider.getUriForFile(
 context,
 "${context.packageName}.FileProvider",
 file
 )
 //赋予权限
 packages.forEach {
 context.grantUriPermission(
 it,
 contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
 )
 }
 return contentUri
 }
 fun getThumbnailFromVideo(path: String, percent: Int = 0): Bitmap? {
 val retriever = MediaMetadataRetriever()
 var bitmap: Bitmap? = null
 try {
 retriever.setDataSource(path)
 val duration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
 ?.toLongOrNull() ?: 0
 val timePositionUs = (duration / 100f * percent).toLong() * 1000
 bitmap = retriever.getFrameAtTime(
 timePositionUs, MediaMetadataRetriever.OPTION_CLOSEST
 )
 } catch (e: Exception) {
 log(type = LogType.E, errorThrowable = e)
 e.printStackTrace()
 } finally {
 retriever.release()
 }
 return bitmap
 }

 

作者:张旭小侠原文地址:https://www.cnblogs.com/zxxiaoxia/p/18373731

%s 个评论

要回复文章请先登录注册