更新记录

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

  • 重要更新: 登录成功现在会返回完整的认证信息
  • ✅ 登录成功回调现在包含 accessTokenopenidexpireTime 字段
  • ✅ 可直接使用返回的 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: 直接返回 accessTokenopenidexpireTime
  • Harmony: 只返回 authCode,需要通过服务端获取完整登录信息

📤 分享功能差异

  • Android/iOS: 使用传统参数(title、desc、imagePath等)
  • Harmony: 使用ark类型分享,需要业务后台提供签名数据

🚫 不支持的功能

  • 隐私协议相关API
  • 获取用户信息
  • 退出登录
  • 视频、网页、音乐分享

🚨 重要提示

⚠️ 必须使用自定义基座运行,否则无法找到插件方法

⚠️ 必须用户同意隐私协议,否则SDK所有功能都无法使用

环境配置

前置条件

  1. QQ互联开放平台申请移动应用
  2. 获取 AppID
  3. 配置应用包名、签名和通用链接

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互联开放平台申请的 AppID
  • uris.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互联开放平台申请的 AppID
  • AuthActivityandroid: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 平台

  • 直接返回完整的登录信息:accessTokenopenidexpireTime
  • 支持隐私协议检查和设置
  • 支持获取用户信息和退出登录

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 平台

  • 支持所有分享类型:文本、图片、视频、网页、音乐
  • 使用传统参数:titledescimagePathvideoUrl
  • 支持分享到QQ好友和QQ空间

Harmony平台

  • 只支持文本和图片分享(ark类型2)
  • 使用专用参数:shareJsontimestampnonceshareJsonSign
  • 需要业务后台提供签名数据

分享类型和场景

分享类型 (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 配置是否正确
  • 确保应用已正确安装并具有处理回调的权限

📞 技术支持

如果在使用过程中遇到问题,请:

  1. 查阅上方常见问题
  2. 参考QQ互联官方开发文档
  3. 检查配置是否正确
  4. 确认QQ客户端版本

祝您开发愉快! 🎉

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率: