# 微信分享返回提示显示“八哥口语”改造备忘

## 背景

当前 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()`。
