258 lines
7.8 KiB
Markdown
258 lines
7.8 KiB
Markdown
# 微信分享返回提示显示“八哥口语”改造备忘
|
||
|
||
## 背景
|
||
|
||
当前 Android 配音分享使用系统 `Intent.ACTION_SEND`,入口位于:
|
||
|
||
```kotlin
|
||
android/sample-app/src/main/java/cn/learningpad/oraltrainer/sample/MainActivity.kt
|
||
```
|
||
|
||
`shareMergedDubbing()` 会构造一个 `ACTION_SEND` Intent,然后通过 `startActivity(Intent.createChooser(...))` 调起微信或其他应用。
|
||
|
||
这种方式下,微信只能识别到“第三方应用通过系统分享调起”,无法可靠关联到微信开放平台登记的 App 信息,因此完成后的返回提示通常显示为“留在微信 / 返回第三方工具”。
|
||
|
||
要让提示变成“返回八哥口语”,需要改为微信官方 OpenSDK 分享,并在微信开放平台完成应用登记。
|
||
|
||
## 目标
|
||
|
||
1. 配音链接通过微信 OpenSDK 分享为网页卡片。
|
||
2. 微信完成页返回提示能识别并显示“八哥口语”。
|
||
3. 保留现有上传分享链接的逻辑,只替换最终调起微信的方式。
|
||
|
||
## 需要提前准备的信息
|
||
|
||
| 项目 | 当前值 |
|
||
|---|---|
|
||
| 应用名称 | 八哥口语 |
|
||
| Android 包名 | `cn.learningpad.oraltrainer.sample` |
|
||
| Gradle namespace | `cn.learningpad.oraltrainer.sample` |
|
||
| 微信回调 Activity 包名 | `cn.learningpad.oraltrainer.sample.wxapi` |
|
||
| 回调 Activity 类名 | `WXEntryActivity` |
|
||
| 本地名称资源 | `android:label="@string/app_name"` |
|
||
|
||
还需要从微信开放平台获取:
|
||
|
||
- 微信 AppID
|
||
- 应用签名 MD5
|
||
- 已审核通过的移动应用信息
|
||
|
||
## 一、微信开放平台登记
|
||
|
||
1. 登录 [微信开放平台](https://open.weixin.qq.com/)。
|
||
2. 进入“管理中心”,创建或打开移动应用。
|
||
3. 填写应用名称为“八哥口语”。
|
||
4. 配置 Android 应用信息:
|
||
- 包名:`cn.learningpad.oraltrainer.sample`
|
||
- 签名:使用正式签名 APK 的应用签名 MD5
|
||
5. 提交审核,等待微信开放平台通过。
|
||
6. 审核通过后记录微信 AppID。
|
||
|
||
注意:微信校验的是正式签名。Debug 构建如果也要联调,需要在开放平台补充 Debug 签名,或临时使用与正式签名一致的构建配置。
|
||
|
||
## 二、获取正式签名 MD5
|
||
|
||
安装已签名的 APK 后执行:
|
||
|
||
```bash
|
||
adb shell dumpsys package cn.learningpad.oraltrainer.sample | grep -A 2 "Signatures"
|
||
```
|
||
|
||
更稳妥的方式是使用微信官方提供的生成签名工具,或在本地用正式 keystore 查询证书指纹:
|
||
|
||
```bash
|
||
keytool -list -v -alias <key-alias> -keystore <keystore-file>
|
||
```
|
||
|
||
将结果中的 `MD5` 去掉冒号并转为小写后填入微信开放平台。
|
||
|
||
## 三、添加微信 OpenSDK
|
||
|
||
修改文件:
|
||
|
||
```text
|
||
android/sample-app/build.gradle.kts
|
||
```
|
||
|
||
在 `dependencies` 中加入:
|
||
|
||
```kotlin
|
||
implementation("com.tencent.mm.opensdk:wechat-sdk-android:6.7.0")
|
||
```
|
||
|
||
建议实施时检查 Maven 上是否有更新稳定版;如果没有特殊需求,可继续固定当前版本,避免 SDK 行为漂移。
|
||
|
||
## 四、初始化微信 API
|
||
|
||
建议在 `MainActivity` 中增加:
|
||
|
||
```kotlin
|
||
private lateinit var wxApi: IWXAPI
|
||
```
|
||
|
||
在创建 Activity 或进入配音功能前初始化:
|
||
|
||
```kotlin
|
||
wxApi = WXAPIFactory.createWXAPI(this, WECHAT_APP_ID, true)
|
||
wxApi.registerApp(WECHAT_APP_ID)
|
||
```
|
||
|
||
`WECHAT_APP_ID` 应放入构建配置、Manifest metadata 或私有配置中,不要硬编码在业务代码里。
|
||
|
||
## 五、替换系统分享调用
|
||
|
||
保留现有 `uploadDubShare()`,拿到 `shareUrl` 后改用:
|
||
|
||
```kotlin
|
||
val webpage = WXWebpageObject().apply {
|
||
webpageUrl = shareUrl
|
||
}
|
||
|
||
val message = WXMediaMessage(webpage).apply {
|
||
title = "我的口语配音"
|
||
description = item.title
|
||
}
|
||
|
||
val request = SendMessageToWX.Req().apply {
|
||
message = message
|
||
transaction = "dub_share"
|
||
scene = SendMessageToWX.Req.WXSceneSession
|
||
}
|
||
|
||
if (!wxApi.sendReq(request)) {
|
||
setDubbingStatus("分享失败:未检测到可用的微信客户端")
|
||
} else {
|
||
setDubbingStatus("已生成分享链接:$shareUrl")
|
||
}
|
||
```
|
||
|
||
如需支持朋友圈,把 `scene` 改为:
|
||
|
||
```kotlin
|
||
SendMessageToWX.Req.WXSceneTimeline
|
||
```
|
||
|
||
当前需求主要是发给好友或群聊,建议先保持 `WXSceneSession`。
|
||
|
||
## 六、新增微信回调 Activity
|
||
|
||
必须严格按包名规则创建:
|
||
|
||
```text
|
||
android/sample-app/src/main/java/cn/learningpad/oraltrainer/sample/wxapi/WXEntryActivity.kt
|
||
```
|
||
|
||
示例内容:
|
||
|
||
```kotlin
|
||
package cn.learningpad.oraltrainer.sample.wxapi
|
||
|
||
import android.app.Activity
|
||
import android.content.pm.PackageManager
|
||
import android.os.Bundle
|
||
import com.tencent.mm.opensdk.modelbase.BaseReq
|
||
import com.tencent.mm.opensdk.modelbase.BaseResp
|
||
import com.tencent.mm.opensdk.openapi.IWXAPI
|
||
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler
|
||
import com.tencent.mm.opensdk.openapi.WXAPIFactory
|
||
|
||
class WXEntryActivity : Activity(), IWXAPIEventHandler {
|
||
private lateinit var api: IWXAPI
|
||
|
||
override fun onCreate(savedInstanceState: Bundle?) {
|
||
super.onCreate(savedInstanceState)
|
||
val info = packageManager.getApplicationInfo(
|
||
packageName,
|
||
PackageManager.GET_META_DATA
|
||
)
|
||
val appId = info.metaData.getString("com.tencent.wechat.APP_ID").orEmpty()
|
||
api = WXAPIFactory.createWXAPI(this, appId, true)
|
||
api.handleIntent(intent, this)
|
||
finish()
|
||
}
|
||
|
||
override fun onReq(req: BaseReq) {}
|
||
|
||
override fun onResp(resp: BaseResp) {
|
||
finish()
|
||
}
|
||
}
|
||
```
|
||
|
||
## 七、注册回调 Activity
|
||
|
||
修改:
|
||
|
||
```text
|
||
android/sample-app/src/main/AndroidManifest.xml
|
||
```
|
||
|
||
在 `<application>` 内添加:
|
||
|
||
```xml
|
||
<activity
|
||
android:name=".wxapi.WXEntryActivity"
|
||
android:exported="true"
|
||
android:label="@string/app_name"
|
||
android:launchMode="singleTop"
|
||
android:taskAffinity="cn.learningpad.oraltrainer.sample"
|
||
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
||
```
|
||
|
||
`android:label="@string/app_name"` 对应中文资源里的“八哥口语”:
|
||
|
||
```text
|
||
android/sample-app/src/main/res/values-zh/strings.xml
|
||
```
|
||
|
||
## 八、配置 AppID
|
||
|
||
推荐方式是在 Manifest 中加:
|
||
|
||
```xml
|
||
<meta-data
|
||
android:name="com.tencent.wechat.APP_ID"
|
||
android:value="${wechatAppId}" />
|
||
```
|
||
|
||
并在 `build.gradle.kts` 中加:
|
||
|
||
```kotlin
|
||
manifestPlaceholders["wechatAppId"] = "替换为微信AppID"
|
||
```
|
||
|
||
正式项目建议不要直接提交真实密钥类配置。虽然微信 AppID 本身不是私钥,但仍更适合放到本地配置或 CI 注入。
|
||
|
||
## 九、验收清单
|
||
|
||
- [ ] 正式签名包安装成功。
|
||
- [ ] 点击“分享配音”后不再走系统分享面板,而是直接拉起微信。
|
||
- [ ] 微信好友会话中出现网页卡片,标题为“我的口语配音”。
|
||
- [ ] 卡片点击后能正常打开配音分享页。
|
||
- [ ] 分享完成后,微信返回提示显示“八哥口语”相关文案,而不是“第三方工具”。
|
||
- [ ] 从微信返回后,八哥口语仍停留在原界面。
|
||
- [ ] 未安装微信时给出明确失败提示,不崩溃。
|
||
- [ ] Debug 与 Release 的包名和签名策略确认无误。
|
||
|
||
## 十、容易踩坑的点
|
||
|
||
1. **包名必须完全一致**
|
||
`WXEntryActivity` 必须放在 `cn.learningpad.oraltrainer.sample.wxapi` 下,否则微信无法回调。
|
||
|
||
2. **签名必须是开放平台登记的那个**
|
||
Debug 签名和 Release 签名不同时,OpenSDK 可能无法正常调起或回调。
|
||
|
||
3. **应用名称以微信开放平台为准**
|
||
只修改 Android 本地 `app_name` 不一定足够;微信返回文案依赖开放平台登记的应用信息。
|
||
|
||
4. **不要删除现有网页分享逻辑**
|
||
`uploadDubShare()` 仍然负责生成服务端分享链接,微信 OpenSDK 只负责把这个链接作为网页对象发送。
|
||
|
||
5. **旧版本微信兼容性**
|
||
如果用户微信版本过低,`sendReq()` 可能返回 false。应给用户明确提示。
|
||
|
||
## 结论
|
||
|
||
这个问题的根因是当前实现使用系统 `ACTION_SEND`,而不是微信官方 OpenSDK。
|
||
要显示“返回八哥口语”,必须完成微信开放平台登记、正式签名绑定,并把分享路径切换为 `IWXAPI.sendReq()`。
|