更新记录
1.0.4(2025-09-02)
支持 鸿蒙平台
1.0.3(2025-08-19)
修复已知问题
1.0.2(2025-08-19)
1.修复已知问题 2.登录成功增加accessToken等返回值
查看更多平台兼容性
uni-app(4.36)
Vue2 | Vue3 | Chrome | Safari | app-vue | app-vue插件版本 | app-nvue | app-nvue插件版本 | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 | 鸿蒙插件版本 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | - | - | - | √ | 1.0.2 | √ | 1.0.2 | 5.0 | 1.0.2 | 12 | 1.0.2 | 15 | 1.0.4 |
微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 快应用-华为 | 快应用-联盟 |
---|---|---|---|---|---|---|---|---|---|---|
- | - | - | - | - | - | - | - | - | - | - |
uni-app x(4.36)
Chrome | Safari | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 | 鸿蒙插件版本 | 微信小程序 |
---|---|---|---|---|---|---|---|---|
× | × | 5.0 | 1.0.0 | 12 | 1.0.0 | 15 | 1.0.4 | × |
tt-qq-sdk
🚀 腾讯QQ SDK插件,为 uni-app x 提供完整的QQ集成解决方案,包含登录、分享、用户信息等功能
🆕 最新更新
v1.0.4
- ✅ Harmony平台支持: 新增Harmony平台完整支持
- ✅ 登录流程优化: Harmony平台支持authCode登录流程
- ✅ 分享功能增强: Harmony平台支持ark类型分享
- ✅ 平台差异说明: 详细说明各平台API差异
- ✅ 错误码完善: 新增Harmony平台专用错误码
v1.0.2
- ✅ 重要更新: 登录成功现在会返回完整的认证信息
- ✅ 登录成功回调现在包含
accessToken
、openid
、expireTime
字段 - ✅ 可直接使用返回的
accessToken
调用QQ开放接口 - ✅ 优化了错误处理和用户体验
📖 目录
SDK版本信息
平台 | 版本 |
---|---|
iOS | 3.5.17.4 |
Android | 3.5.17.3 |
Harmony | 1.0.3 |
📚 推荐阅读: QQ互联官方开发文档
平台支持说明
支持平台
- ✅ Android - 完整功能支持
- ✅ iOS - 完整功能支持
- ✅ Harmony - 部分功能支持(登录、分享)
平台差异对比
功能 | Android | iOS | Harmony |
---|---|---|---|
基础功能 | |||
SDK初始化 | ✅ | ✅ | ✅ |
检测QQ安装 | ✅ | ✅ | ✅ |
登录功能 | |||
隐私协议检查 | ✅ | ✅ | ❌ |
设置隐私协议 | ✅ | ✅ | ❌ |
QQ登录 | ✅ | ✅ | ✅ |
获取用户信息 | ✅ | ✅ | ❌ |
退出登录 | ✅ | ✅ | ❌ |
分享功能 | |||
文本分享 | ✅ | ✅ | ✅ |
图片分享 | ✅ | ✅ | ✅ |
视频分享 | ✅ | ✅ | ❌ |
网页分享 | ✅ | ✅ | ❌ |
音乐分享 | ✅ | ✅ | ❌ |
Harmony平台特殊说明
🔐 登录流程差异
- Android/iOS: 直接返回
accessToken
、openid
、expireTime
- Harmony: 只返回
authCode
,需要通过服务端获取完整登录信息
📤 分享功能差异
- Android/iOS: 使用传统参数(title、desc、imagePath等)
- Harmony: 使用ark类型分享,需要业务后台提供签名数据
🚫 不支持的功能
- 隐私协议相关API
- 获取用户信息
- 退出登录
- 视频、网页、音乐分享
🚨 重要提示
⚠️ 必须使用自定义基座运行,否则无法找到插件方法
⚠️ 必须用户同意隐私协议,否则SDK所有功能都无法使用
环境配置
前置条件
- 在QQ互联开放平台申请移动应用
- 获取
AppID
- 配置应用包名、签名和通用链接
iOS平台配置
1. 配置 URL Scheme
在项目根目录的 Info.plist
文件中添加以下配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- 允许查询QQ应用 -->
<key>LSApplicationQueriesSchemes</key>
<array>
<string>mqqapi</string>
<string>mqq</string>
<string>mqqOpensdkSSoLogin</string>
<string>mqqconnect</string>
<string>mqqopensdkdataline</string>
<string>mqqopensdkgrouptribeshare</string>
<string>mqqopensdkfriend</string>
<string>mqqopensdkapi</string>
<string>mqqopensdkapiV2</string>
<string>mqqopensdkapiV3</string>
<string>mqzoneopensdk</string>
<string>wtloginmqq</string>
<string>wtloginmqq2</string>
<string>mqqwpa</string>
<string>mqzone</string>
<string>mqzonev2</string>
<string>mqzoneshare</string>
<string>wtloginqzone</string>
<string>mqzonewx</string>
<string>mqzoneopensdkapiV2</string>
<string>mqzoneopensdkapi19</string>
<string>mqzoneopensdkapi</string>
<string>mqzoneopensdk</string>
</array>
<!-- URL Scheme 配置 -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>QQ</string>
<key>CFBundleURLSchemes</key>
<array>
<!-- 这里填写您在QQ互联申请的 AppID,格式为: tencent + AppID -->
<string>tencent您的QQ_AppID</string>
</array>
</dict>
</array>
</dict>
</plist>
2. 配置通用链接 (Universal Link)
📖 详细配置请参考: uni官方文档-通用链接
Harmony平台配置
1. 配置 module.json5
在项目根目录的 harmony-configs/entry/src/main/module.json5
文件中添加以下配置:
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"querySchemes": [
"https",
"qqopenapi"
],
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home",
"entity.system.browsable"
],
"actions": [
"action.system.home",
"ohos.want.action.viewData"
],
"uris": [
{
"scheme": "qqopenapi", // 接收 QQ 回调数据
"host": "您的QQ_AppID", // 业务申请的互联 appId,如果填错会导致 QQ 无法回调
"pathRegex": "\\b(auth|share)\\b",
"linkFeature": "Login"
}
]
}
]
}
],
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
}
}
2. 重要配置说明
⚠️ 关键配置项:
querySchemes
: 必须包含"qqopenapi"
用于处理QQ回调uris.scheme
: 必须设置为"qqopenapi"
uris.host
: 必须填写您在QQ互联开放平台申请的 AppIDuris.pathRegex
: 用于匹配登录和分享回调路径requestPermissions
: 必须申请网络权限
⚠️ 注意事项:
- 确保在QQ互联开放平台正确配置应用包名和签名
host
字段必须与QQ互联开放平台配置的AppID完全一致- 测试时请使用与平台配置相同的签名文件
Android平台配置
1. 配置 AndroidManifest.xml
在项目根目录的 AndroidManifest.xml
文件中添加以下配置:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="您的应用包名">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application>
<!-- QQ授权Activity -->
<activity
android:name="com.tencent.tauth.AuthActivity"
android:exported="true"
android:launchMode="singleTask"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- 这里填写您在QQ互联申请的AppID,注意不需要tencent前缀 -->
<data android:scheme="您的QQ_AppID" />
</intent-filter>
</activity>
<!-- QQ分享Activity -->
<activity
android:name="com.tencent.connect.common.AssistActivity"
android:exported="true"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
</application>
</manifest>
2. 重要配置说明
⚠️ 关键配置项:
android:scheme
必须填写您在QQ互联开放平台申请的 AppIDAuthActivity
的android:exported="true"
必须设置,否则无法接收QQ回调AssistActivity
用于处理分享功能,必须包含
⚠️ 注意事项:
- 确保在QQ互联开放平台正确配置应用包名和签名
- 测试时请使用与平台配置相同的签名文件
- Android平台的scheme配置与iOS不同,不需要添加"tencent"前缀
快速开始
1. 导入插件
import { getTTQQSDK } from '@/uni_modules/tt-qq-sdk/utssdk/interface.uts'
export default {
data() {
return {
qqSDK: null as any,
}
},
onLoad() {
// 获取QQ SDK实例
this.qqSDK = getTTQQSDK()
// 注册QQ SDK
this.initQQSDK()
},
methods: {
// 初始化QQ SDK
initQQSDK() {
// SDK初始化代码见下方
}
}
}
2. 初始化 SDK
initQQSDK() {
if (!this.qqSDK) {
console.error('QQ SDK初始化失败')
return
}
// 设置用户已同意隐私协议(必须)
this.qqSDK.setIsAgreedAuthorization(true)
this.qqSDK.register({
appid: "您的QQ_AppID", // 必填:QQ互联申请的AppID
universalLink: "您的通用链接", // iOS必填:通用链接
success: (res) => {
console.log("✅ QQ SDK初始化成功");
// 可以在这里进行后续操作,如检测QQ是否安装
this.checkQQInstalled()
},
fail: (err) => {
console.error("❌ QQ SDK初始化失败:", err);
uni.showToast({
title: 'QQ SDK初始化失败',
icon: 'error'
})
}
});
}
基础使用
检测QQ是否安装
checkQQInstalled() {
const isInstalled = this.qqSDK?.isInstall()
if (!isInstalled) {
uni.showModal({
title: '提示',
content: '请先安装QQ客户端',
showCancel: false
})
return false
}
return true
}
隐私协议检查
checkPrivacyAgreement() {
const isAgreed = this.qqSDK?.isAgreedAuthorization()
if (!isAgreed) {
uni.showModal({
title: '隐私协议',
content: '使用QQ功能需要同意隐私授权协议',
showCancel: false
})
return false
}
return true
}
功能介绍
QQ登录授权
💡 QQ登录需要用户先同意隐私协议,然后进行授权操作
平台差异说明
Android/iOS 平台
- 直接返回完整的登录信息:
accessToken
、openid
、expireTime
- 支持隐私协议检查和设置
- 支持获取用户信息和退出登录
Harmony平台
- 只返回
authCode
,需要通过服务端获取完整登录信息 - 不支持隐私协议相关API
- 不支持获取用户信息和退出登录
参数说明
TTQQLoginOptions
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
success | function | ❌ | 登录成功回调函数 |
fail | function | ❌ | 登录失败回调函数 |
complete | function | ❌ | 登录完成回调函数 |
返回值 TTQQLoginSuccess
参数 | 类型 | 说明 | 平台支持 |
---|---|---|---|
accessToken | string | Access Token凭证,用于后续访问各开放接口 | Android/iOS |
expireTime | string | Access Token的失效期 | Android/iOS |
openid | string | 用户授权登录后对该用户的唯一标识 | Android/iOS |
authCode | string | 授权码,Harmony平台专用 | Harmony |
示例代码
Android/iOS 平台登录
// QQ登录
handleQQLogin() {
// 先检查QQ是否安装
if (!this.checkQQInstalled()) {
return
}
// 检查隐私协议
if (!this.checkPrivacyAgreement()) {
return
}
this.qqSDK?.login({
success: (res) => {
console.log("✅ QQ登录成功:", res);
console.log("AccessToken:", res.accessToken);
console.log("OpenID:", res.openid);
console.log("过期时间:", res.expireTime);
// 保存登录信息
uni.setStorageSync('qqLoginInfo', {
"accessToken": res.accessToken,
"openid": res.openid,
"expireTime": res.expireTime
} as UTSJSONObject);
// 登录成功后获取用户信息
this.getUserInfo()
},
fail: (err) => {
console.error("❌ QQ登录失败:", err);
this.handleLoginError(err)
},
complete: (res) => {
console.log("QQ登录完成:", res);
}
});
}
Harmony平台登录
// Harmony平台QQ登录
handleHarmonyQQLogin() {
// 检查QQ是否安装
if (!this.checkQQInstalled()) {
return
}
this.qqSDK?.login({
success: (res) => {
console.log("✅ Harmony平台QQ登录成功");
console.log("AuthCode:", res.authCode);
// 保存authCode
uni.setStorageSync('qqLoginInfo', {
"authCode": res.authCode,
"platform": "harmony"
} as UTSJSONObject);
// 通过服务端获取完整登录信息
this.getTokenFromServer(res.authCode);
},
fail: (err) => {
console.error("❌ Harmony平台QQ登录失败:", err);
this.handleLoginError(err)
}
});
}
// 通过authCode从服务端获取token
getTokenFromServer(authCode: string) {
uni.request({
url: 'https://your-server.com/api/qq/getToken',
method: 'POST',
data: {
authCode: authCode,
appId: "您的QQ平台AppID"
},
success: (res) => {
console.log("✅ 获取token成功:", res.data);
// 保存完整的登录信息
uni.setStorageSync('qqLoginInfo', {
"accessToken": res.data.accessToken,
"openid": res.data.openid,
"expireTime": res.data.expireTime,
"platform": "harmony"
} as UTSJSONObject);
uni.showToast({
title: '登录成功',
icon: 'success'
});
},
fail: (err) => {
console.error("❌ 获取token失败:", err);
uni.showToast({
title: '获取登录信息失败',
icon: 'error'
});
}
});
}
跨平台兼容登录
// 兼容所有平台的登录方法
handleUniversalLogin() {
if (!this.checkQQInstalled()) {
return
}
// #ifndef APP-HARMONY
// Android/iOS 平台需要检查隐私协议
if (!this.checkPrivacyAgreement()) {
return
}
// #endif
this.qqSDK?.login({
success: (res) => {
// #ifndef APP-HARMONY
// Android/iOS 平台处理
console.log("AccessToken:", res.accessToken);
console.log("OpenID:", res.openid);
console.log("过期时间:", res.expireTime);
uni.setStorageSync('qqLoginInfo', {
"accessToken": res.accessToken,
"openid": res.openid,
"expireTime": res.expireTime
} as UTSJSONObject);
this.getUserInfo();
// #endif
// #ifdef APP-HARMONY
// Harmony平台处理
console.log("AuthCode:", res.authCode);
uni.setStorageSync('qqLoginInfo', {
"authCode": res.authCode,
"platform": "harmony"
} as UTSJSONObject);
this.getTokenFromServer(res.authCode);
// #endif
},
fail: (err) => {
this.handleLoginError(err);
}
});
}
// 处理登录错误
handleLoginError(error: any) {
const errCode = error.errCode;
const errMsg = error.errMsg;
switch(errCode) {
case 201:
console.log('用户取消登录');
break;
case 202:
uni.showToast({
title: '登录失败',
icon: 'error'
});
break;
case 203:
uni.showModal({
title: '隐私协议',
content: '使用QQ功能需要同意隐私授权协议',
showCancel: false
});
break;
default:
uni.showToast({
title: errMsg || '登录失败',
icon: 'error'
});
break;
}
}
使用登录信息
登录成功后,您将获得以下重要信息:
// 处理登录成功信息
handleLoginSuccess(loginResult: any) {
const { accessToken, openid, expireTime } = loginResult;
// 保存到本地存储
uni.setStorageSync('qqLoginInfo', {
accessToken,
openid,
expireTime: parseInt(expireTime) // 转换为时间戳
});
// 检查token是否过期
const now = Date.now() / 1000;
const expired = parseInt(expireTime) < now;
if (expired) {
console.log('⚠️ Token已过期,需要重新登录');
this.reLogin();
return;
}
// Token有效,可以使用accessToken调用QQ开放接口
console.log('✅ Token有效,可以进行后续操作');
// 获取用户详细信息
this.getUserInfo();
}
// 获取保存的登录信息
getStoredLoginInfo() {
const loginInfo = uni.getStorageSync('qqLoginInfo') as UTSJSONObject | null;
if (loginInfo != null && loginInfo["accessToken"] != null) {
// 检查是否过期
const now = Date.now() / 1000;
const expireTime = loginInfo["expireTime"] as string;
if (parseInt(expireTime) > now) {
return loginInfo;
} else {
// 清除过期信息
uni.removeStorageSync('qqLoginInfo');
return null;
}
}
return null;
}
// 使用accessToken调用QQ开放接口(示例)
allQQApi(apiPath: string, params: any = {}) {
const loginInfo = this.getStoredLoginInfo();
if (!loginInfo) {
console.error('未登录或token已过期');
return null;
}
try {
const response = await uni.request({
url: `https://graph.qq.com/${apiPath}`,
data: {
access_token: loginInfo["accessToken"],
oauth_consumer_key: loginInfo["openid"],
openid: loginInfo["openid"]
//...params
}
});
return response.data;
} catch (error) {
console.error('调用QQ API失败:', error);
return null;
}
}
获取用户信息
💡 获取QQ用户信息(需要先登录成功)
参数说明
TTQQGetUserInfoOptions
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
success | function | ❌ | 获取成功回调函数 |
fail | function | ❌ | 获取失败回调函数 |
complete | function | ❌ | 获取完成回调函数 |
返回值 TTQQGetUserInfoSuccess
参数 | 类型 | 说明 |
---|---|---|
response | Map<String, any> | 用户信息数据,包含昵称、头像等 |
示例代码
// 获取用户信息
getUserInfo() {
this.qqSDK?.getUserInfo({
success: (res) => {
console.log("✅ 获取用户信息成功:", res.response);
// 常用用户信息字段
const nickname = res.response.get('nickname'); // 昵称
const figureurl = res.response.get('figureurl_qq_1'); // 头像URL
const gender = res.response.get('gender'); // 性别
const province = res.response.get('province'); // 省份
const city = res.response.get('city'); // 城市
// 处理用户信息
this.handleUserInfo({
nickname,
avatar: figureurl,
gender,
province,
city
});
},
fail: (err) => {
console.error("❌ 获取用户信息失败:", err);
uni.showToast({
title: '获取用户信息失败',
icon: 'error'
});
},
complete: (res) => {
console.log("获取用户信息完成:", res);
}
});
}
// 处理用户信息
handleUserInfo(userInfo: any) {
// 保存用户信息到本地存储
uni.setStorageSync('qqUserInfo', userInfo);
// 更新页面显示
this.userInfo = userInfo;
// 跳转到主页面或其他操作
uni.switchTab({
url: '/pages/tabBar/home/home'
});
}
QQ分享功能
💡 支持分享文本、图片、视频、网页、音乐到QQ好友或QQ空间
平台差异说明
Android/iOS 平台
- 支持所有分享类型:文本、图片、视频、网页、音乐
- 使用传统参数:
title
、desc
、imagePath
、videoUrl
等 - 支持分享到QQ好友和QQ空间
Harmony平台
- 只支持文本和图片分享(ark类型2)
- 使用专用参数:
shareJson
、timestamp
、nonce
、shareJsonSign
- 需要业务后台提供签名数据
分享类型和场景
分享类型 (type)
0
- 纯文本分享 ✅ 所有平台1
- 图片分享 ✅ 所有平台2
- 视频分享 ❌ Harmony不支持3
- 新闻/网页分享 ❌ Harmony不支持4
- 音乐分享 ❌ Harmony不支持
分享场景 (scene)
0
- 分享到QQ好友 ✅ 所有平台1
- 分享到QQ空间 ✅ 所有平台
参数说明
TTQQShareOptions
参数 | 类型 | 必填 | 说明 | 平台支持 |
---|---|---|---|---|
通用参数 | ||||
type | number | ✅ | 分享类型,见上表 | 所有平台 |
scene | number | ✅ | 分享场景,见上表 | 所有平台 |
Android/iOS 专用参数 | ||||
title | string | 条件 | 分享标题(纯文本时最长1536字符,其他类型最长30字符) | Android/iOS |
desc | string | 条件 | 分享描述(最长40字符,纯文本分享不需要) | Android/iOS |
imagePath | string | 条件 | 图片本地路径(图片分享时必填,限制5M) | Android/iOS |
previewImagePath | string | 条件 | 预览图本地路径(限制1M) | Android/iOS |
videoUrl | string | 条件 | 视频地址(视频分享时必填) | Android/iOS |
musicUrl | string | 条件 | 音乐地址(音乐分享时必填) | Android/iOS |
href | string | 条件 | 网页链接(网页分享时必填) | Android/iOS |
Harmony平台专用参数 | ||||
shareJson | string | ✅ | 分享业务数据JSON字符串(Harmony平台必需) | Harmony |
timestamp | number | ✅ | 分享时的当前时间戳(Harmony平台必需) | Harmony |
nonce | number | ✅ | 随机自然数(Harmony平台必需) | Harmony |
shareJsonSign | string | ✅ | shareJson + timestamp + nonce 三部分签名(Harmony平台必需) | Harmony |
openId | string | ❌ | 用户openid(Harmony平台分享时需要) | Harmony |
使用示例
1. 分享文本
shareText() {
this.qqSDK?.share({
type: 0,
scene: 0, // 分享到QQ好友
title: '这是一条文本消息',
success: (res) => {
console.log('✅ 文本分享成功');
uni.showToast({ title: '分享成功' });
},
fail: (err) => {
console.error('❌ 分享失败:', err);
uni.showToast({ title: '分享失败', icon: 'error' });
}
});
}
2. 分享图片
shareImage() {
this.qqSDK?.share({
type: 1,
scene: 1, // 分享到QQ空间
title: '图片标题',
desc: '图片描述',
imagePath: '/static/share-image.jpg', // 本地图片路径
previewImagePath: '/static/preview-image.jpg', // 预览图路径
success: (res) => {
console.log('✅ 图片分享成功');
},
fail: (err) => {
console.error('❌ 图片分享失败:', err);
}
});
}
3. 分享网页
shareWebPage() {
this.qqSDK?.share({
type: 3,
scene: 0,
title: '网页标题',
desc: '网页描述',
href: 'https://www.example.com',
previewImagePath: '/static/webpage-thumb.jpg',
success: (res) => {
console.log('✅ 网页分享成功');
},
fail: (err) => {
console.error('❌ 网页分享失败:', err);
}
});
}
Harmony平台分享示例
// Harmony平台分享文本
shareTextHarmony() {
// 从业务后台获取分享参数
const shareParams = this.getHarmonyShareParams('text', {
title: 'Harmony平台文本分享',
content: '这是Harmony平台的文本分享内容'
});
this.qqSDK?.share({
type: 0,
scene: 0,
// Harmony平台必需参数
shareJson: shareParams.shareJson,
timestamp: shareParams.timestamp,
nonce: shareParams.nonce,
shareJsonSign: shareParams.shareJsonSign,
openId: shareParams.openId,
success: (res) => {
console.log('✅ Harmony平台文本分享成功');
},
fail: (err) => {
console.error('❌ Harmony平台分享失败:', err);
}
});
}
// Harmony平台分享图片
shareImageHarmony() {
const shareParams = this.getHarmonyShareParams('image', {
title: 'Harmony平台图片分享',
summary: '这是Harmony平台的图片分享',
picture_url: 'https://example.com/image.jpg'
});
this.qqSDK?.share({
type: 1,
scene: 0,
// Harmony平台必需参数
shareJson: shareParams.shareJson,
timestamp: shareParams.timestamp,
nonce: shareParams.nonce,
shareJsonSign: shareParams.shareJsonSign,
openId: shareParams.openId,
success: (res) => {
console.log('✅ Harmony平台图片分享成功');
},
fail: (err) => {
console.error('❌ Harmony平台分享失败:', err);
}
});
}
// 从业务后台获取Harmony分享参数
getHarmonyShareParams(type: string, content: any) {
// 构建shareJson数据
const shareData = {
"msg_style": 0,
"title": content.title,
"summary": content.summary || content.content,
"brief": "互联分享",
"url": content.url || "https://www.dcloud.io/",
"picture_url": content.picture_url || ""
};
return {
shareJson: JSON.stringify(shareData),
timestamp: Date.now(),
nonce: Math.floor(Math.random() * 1000000), // 随机自然数
shareJsonSign: "mock_signature_for_test", // 实际使用时需要后台签名
openId: "test_openid_123456"
};
}
跨平台兼容分享
// 兼容所有平台的分享方法
shareUniversal(type: number, content: any) {
const shareParams = {
type: type,
scene: 0,
// Android/iOS 参数
title: content.title,
desc: content.desc,
imagePath: content.imagePath,
previewImagePath: content.previewImagePath,
videoUrl: content.videoUrl,
musicUrl: content.musicUrl,
href: content.href,
// Harmony平台参数(其他平台会忽略)
shareJson: this.getHarmonyShareJson(type, content),
timestamp: Date.now(),
nonce: Math.floor(Math.random() * 1000000), // 随机自然数
shareJsonSign: "mock_signature_for_test",
openId: "test_openid_123456",
success: (res) => {
console.log('✅ 分享成功');
},
fail: (err) => {
console.error('❌ 分享失败:', err);
}
};
this.qqSDK?.share(shareParams);
}
// 生成Harmony平台的shareJson
getHarmonyShareJson(type: number, content: any) {
const shareData = {
"msg_style": 0,
"title": content.title,
"summary": content.desc || content.summary,
"brief": "互联分享"
};
if (type === 1 && content.imagePath) {
shareData["picture_url"] = content.imagePath;
}
if (content.href) {
shareData["url"] = content.href;
}
return JSON.stringify(shareData);
}
Harmony平台特殊说明
🔐 登录流程详解
Harmony平台的QQ登录流程与Android/iOS有显著差异:
1. 登录流程对比
Android/iOS 平台:
用户点击登录 → SDK直接返回完整信息 → 保存到本地
返回:accessToken, openid, expireTime
Harmony平台:
用户点击登录 → SDK返回authCode → 调用服务端获取token → 保存到本地
返回:authCode → 服务端处理 → accessToken, openid, expireTime
2. 服务端接口要求
请求格式:
POST /api/qq/getToken
{
"authCode": "Harmony平台返回的授权码",
"appId": "您的QQ平台AppID"
}
响应格式:
{
"code": 0,
"message": "success",
"data": {
"accessToken": "获取到的访问令牌",
"openid": "用户唯一标识",
"expireTime": "过期时间戳"
}
}
📤 分享功能详解
1. 分享类型限制
Harmony平台只支持ark类型分享,具体限制如下:
分享类型 | Harmony支持 | 说明 |
---|---|---|
文本分享 | ✅ | 支持ark类型文本分享 |
图片分享 | ✅ | 支持ark类型图片分享 |
视频分享 | ❌ | 不支持 |
网页分享 | ❌ | 不支持 |
音乐分享 | ❌ | 不支持 |
2. 分享参数结构
Harmony平台使用ark类型分享,需要以下参数:
// shareJson 数据结构
{
"msg_style": 0,
"title": "分享标题",
"summary": "分享描述",
"brief": "互联分享",
"url": "https://www.example.com",
"picture_url": "https://example.com/image.jpg"
}
3. 签名计算
Harmony平台需要业务后台计算签名:
// 服务端签名计算示例
const shareJson = JSON.stringify(shareData);
const timestamp = Date.now();
const nonce = Math.floor(Math.random() * 1000000); // 随机自然数
const signString = shareJson + timestamp + nonce;
const shareJsonSign = calculateSignWithAppKey(signString);
🚫 不支持的功能
Harmony平台不支持以下功能:
1. 隐私协议相关
isAgreedAuthorization()
- 获取授权状态setIsAgreedAuthorization()
- 设置授权状态
2. 用户信息相关
getUserInfo()
- 获取用户信息
3. 登录管理相关
logout()
- 退出登录
4. 分享类型限制
- 视频分享(type: 2)
- 网页分享(type: 3)
- 音乐分享(type: 4)
🔧 开发建议
1. 条件编译使用
// 使用条件编译处理平台差异
// #ifndef APP-HARMONY
// Android/iOS 平台代码
this.qqSDK?.getUserInfo({
success: (res) => {
console.log("用户信息:", res);
}
});
// #endif
// #ifdef APP-HARMONY
// Harmony平台代码
console.log("Harmony平台不支持获取用户信息");
// #endif
2. 错误处理
// Harmony平台专用错误码
switch(errCode) {
case 501:
console.log("shareJson参数不能为空");
break;
case 502:
console.log("timestamp参数不能为空");
break;
case 503:
console.log("nonce参数不能为空");
break;
case 504:
console.log("shareJsonSign参数不能为空");
break;
case 505:
console.log("Harmony平台只支持文本和图片分享");
break;
}
3. 服务端集成
// Harmony平台需要服务端支持
class HarmonyQQService {
async getTokenFromServer(authCode: string) {
const response = await fetch('/api/qq/getToken', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
authCode: authCode,
appId: process.env.QQ_APP_ID
})
});
return await response.json();
}
async getShareParams(content: any) {
const response = await fetch('/api/qq/getShareParams', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(content)
});
return await response.json();
}
// 生成分享参数
generateShareParams(shareData: any) {
const shareJson = JSON.stringify(shareData);
const timestamp = Date.now();
const nonce = Math.floor(Math.random() * 1000000); // 随机自然数
const signString = shareJson + timestamp + nonce;
const shareJsonSign = this.calculateSign(signString);
return {
shareJson,
timestamp,
nonce,
shareJsonSign
};
}
private calculateSign(signString: string): string {
// 使用AppKey进行签名计算
// 这里需要根据实际的签名算法实现
return "calculated_signature";
}
}
退出登录
💡 退出QQ登录状态
平台支持说明
- ✅ Android/iOS: 支持退出登录功能
- ❌ Harmony: 不支持退出登录功能
参数说明
TTQQLogoutOptions
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
success | function | ❌ | 退出成功回调函数 |
fail | function | ❌ | 退出失败回调函数 |
complete | function | ❌ | 退出完成回调函数 |
示例代码
// 退出登录
handleLogout() {
this.qqSDK?.logout({
success: (res) => {
console.log("✅ 退出登录成功:", res);
// 清除本地用户信息和登录信息
uni.removeStorageSync('qqUserInfo');
uni.removeStorageSync('qqLoginInfo');
// 重置页面状态
this.userInfo = null;
// 跳转到登录页面或首页
uni.navigateTo({
url: '/pages/login/login'
});
},
fail: (err) => {
console.error("❌ 退出登录失败:", err);
uni.showToast({
title: '退出失败',
icon: 'error'
});
},
complete: (res) => {
console.log("退出登录完成:", res);
}
});
}
错误处理
错误码说明
错误码 | 错误信息 | 适用场景 | 解决方案 |
---|---|---|---|
基础错误 | |||
101 | 未安装QQ | 所有功能 | 提示用户安装QQ客户端 |
102 | SDK未初始化或初始化失败 | 所有功能 | 检查SDK初始化参数,重新注册 |
203 | 未同意隐私政策 | 所有功能 | 提示用户同意隐私授权协议 |
登录错误 | |||
201 | 取消登录 | 登录功能 | 用户主动取消,无需处理 |
202 | 登录失败 | 登录功能 | 检查网络和QQ客户端状态 |
204 | 网络异常 | 登录功能 | 检查网络连接 |
用户信息错误 | |||
301 | 获取用户信息失败 | 获取用户信息 | 确保已登录,检查网络状态 |
分享错误 | |||
401 | title不能为空 | 分享功能 | 提供分享标题 |
402 | imagePath不能为空 | 图片分享 | 提供有效的本地图片路径 |
403 | 预览图片获取失败 | 分享功能 | 检查预览图路径和文件 |
404 | desc不能为空 | 分享功能 | 提供分享描述(纯文本分享除外) |
405 | 预览图不能为空 | iOS分享 | iOS平台分享时必须提供预览图 |
406 | videoUrl不能为空 | 视频分享 | 提供有效的视频链接 |
407 | href不能为空 | 网页分享 | 提供有效的网页链接 |
408 | 视频获取失败 | 视频分享 | 检查视频URL有效性 |
Harmony平台专用错误 | |||
501 | shareJson参数不能为空 | Harmony分享 | 提供shareJson参数 |
502 | timestamp参数不能为空 | Harmony分享 | 提供timestamp参数 |
503 | nonce参数不能为空 | Harmony分享 | 提供nonce参数 |
504 | shareJsonSign参数不能为空 | Harmony分享 | 提供shareJsonSign参数 |
505 | Harmony平台只支持文本和图片分享 | Harmony分享 | 使用支持的分享类型 |
其他错误 | |||
999 | 其他错误 | 所有功能 | 查看原始错误信息和详细日志 |
错误处理最佳实践
// 统一错误处理函数
handleQQError(error: any, action: string) {
console.error(`❌ ${action}失败:`, error);
// 获取错误码和错误信息
const errCode = error.errCode || error.code;
const errMsg = error.errMsg || error.message;
switch(errCode) {
case 101:
uni.showModal({
title: 'QQ未安装',
content: '请先安装QQ客户端后再试',
showCancel: false,
confirmText: '知道了'
});
break;
case 102:
uni.showModal({
title: 'SDK初始化失败',
content: '请检查QQ AppID配置是否正确',
showCancel: false
});
break;
case 203:
uni.showModal({
title: '隐私协议',
content: '使用QQ功能需要同意隐私授权协议',
showCancel: false
});
break;
case 201:
// 用户取消,不显示错误提示
console.log('用户取消操作');
break;
case 202:
case 204:
uni.showToast({
title: '登录失败,请重试',
icon: 'error'
});
break;
case 301:
uni.showToast({
title: '获取用户信息失败',
icon: 'error'
});
break;
case 401:
case 402:
case 404:
case 405:
case 406:
case 407:
uni.showToast({
title: '分享参数不完整',
icon: 'error'
});
break;
case 403:
case 408:
uni.showToast({
title: '文件获取失败',
icon: 'error'
});
break;
case 999:
// 其他错误,显示具体错误信息
uni.showToast({
title: errMsg || '操作失败',
icon: 'error'
});
break;
default:
// QQ SDK原始错误
if (errMsg && errMsg !== '用户取消') {
uni.showToast({
title: errMsg,
icon: 'error'
});
}
break;
}
}
// 使用示例
this.qqSDK?.login({
success: (result) => {
console.log('登录成功:', result);
},
fail: (error) => {
this.handleQQError(error, 'QQ登录');
}
});
调试技巧
// 开发环境下打印详细错误信息
debugQQError(error: any) {
if (process.env.NODE_ENV === 'development') {
console.group('🐛 QQ SDK错误详情');
console.log('错误码:', error.errCode || error.code);
console.log('错误信息:', error.errMsg || error.message);
console.log('错误主体:', error.errSubject);
console.log('原始错误:', error.cause);
console.groupEnd();
}
}
常见问题
1. 找不到插件方法?
解决方案: 确保使用自定义基座运行,标准基座不包含原生插件。
2. iOS平台登录/分享无响应?
解决方案:
- 检查 Info.plist 中的 URL Scheme 配置
- 确认通用链接配置正确
- 验证QQ互联开放平台的 iOS 应用配置
- 确保 URL Scheme 格式为
tencent + AppID
3. Android平台功能异常?
解决方案:
- 确认应用签名与QQ互联开放平台配置一致
- 检查包名是否正确
- 确保QQ客户端版本支持相关功能
4. 提示未同意隐私协议?
解决方案:
- 在初始化SDK前调用
setIsAgreedAuthorization(true)
- 确保用户已明确同意隐私授权协议
- 检查隐私协议相关的UI流程
5. 分享图片失败?
解决方案:
- 确保图片路径为本地路径,不支持网络图片
- 检查图片文件是否存在
- 图片大小不要超过限制(分享图片5M,预览图1M)
- iOS平台必须提供预览图
6. 获取用户信息失败?
解决方案:
- 确保已成功登录
- 检查网络连接状态
- 确认用户授权了相应的权限
- 验证QQ客户端是否为最新版本
7. 通用链接配置问题?
解决方案:
- 确保域名支持HTTPS
- 验证apple-app-site-association文件配置正确
- 检查苹果开发者账号中的Associated Domains配置
- 测试通用链接是否能正常跳转
8. QQ客户端版本兼容性?
解决方案:
- 建议使用最新版本的QQ客户端
- 某些功能可能需要特定版本的QQ支持
- 在功能使用前先检查QQ是否安装
9. Harmony平台登录只返回authCode?
解决方案:
- 这是Harmony平台的正常行为,需要调用服务端接口获取完整登录信息
- 实现服务端的token获取接口
- 使用authCode调用QQ互联平台的token接口
10. Harmony平台分享失败?
解决方案:
- 检查是否提供了所有必需参数:shareJson、timestamp、nonce、shareJsonSign
- 确保shareJson格式正确,符合ark类型要求
- 验证服务端签名计算是否正确
- 确认只使用了支持的分享类型(文本、图片)
11. Harmony平台不支持某些功能?
解决方案:
- 使用条件编译处理平台差异
- 对于不支持的功能,提供替代方案或提示用户
- 参考平台支持说明表格,了解功能支持情况
12. 如何实现跨平台兼容?
解决方案:
- 使用条件编译
#ifdef APP-HARMONY
和#ifndef APP-HARMONY
- 为不同平台提供不同的参数和逻辑
- 在接口调用时包含所有平台的参数,让SDK自动选择
13. Harmony平台配置问题?
解决方案:
- 检查
module.json5
中的querySchemes
是否包含"qqopenapi"
- 确认
uris.host
字段与QQ互联开放平台的AppID完全一致 - 验证
uris.scheme
设置为"qqopenapi"
- 确保已申请
ohos.permission.INTERNET
网络权限 - 检查
pathRegex
是否正确匹配回调路径
14. Harmony平台QQ回调失败?
解决方案:
- 确认
module.json5
中的host
字段与QQ互联开放平台配置一致 - 检查应用签名是否与QQ互联开放平台配置匹配
- 验证
uris
配置是否正确 - 确保应用已正确安装并具有处理回调的权限
📞 技术支持
如果在使用过程中遇到问题,请:
- 查阅上方常见问题
- 参考QQ互联官方开发文档
- 检查配置是否正确
- 确认QQ客户端版本
祝您开发愉快! 🎉