HarmonyOS鸿蒙Next中QQ分享功能,我这样分享过后,QQ那边显示分享失败是为什么,求助各位大佬

HarmonyOS鸿蒙Next中QQ分享功能,我这样分享过后,QQ那边显示分享失败是为什么,求助各位大佬

import {
  IQQOpenApi,
  OpenApiConfig,
  QQOpenApiFactory,
  ShareData,
  ShareResult,
  ShareResultType } from '@tencent/qq-open-sdk'
import { promptAction } from '@kit.ArkUI'
import { BusinessError } from '@kit.BasicServicesKit'
import { Logger } from 'accomponentitembase'
import { buffer, util } from '@kit.ArkTS'
import { cryptoFramework } from '@kit.CryptoArchitectureKit'

export class QQUtil {
  static appId = 111111111
  private static qqOpenApi: IQQOpenApi

  /**
   * 分享
   * @param title 标题
   * @param summary 内容
   * @param brief QQ信息列表显示的内容
   * @param imageUrl 图片链接
   * @param url 跳转链接
   */
  static async share(title: string, summary: string, brief: string, imageUrl: string, url: string) {


    let content = new Object({
      msg_style: 0,
      title: title,
      summary: summary,
      brief: brief,
      url: url,
      picture_url: imageUrl
    })
    let shareData: ShareData = new ShareData()
    shareData.timestamp = Date.parse(new Date().toString()) / 1000
    shareData.nonce = Math.floor(Math.random() * 100000000 + 100)
    shareData.shareJson = JSON.stringify(content)
    let signContent = 'POSTconnect.qq.com/share?appid=' + QQUtil.appId.toString()
      + '&nonce=' + shareData.nonce.toString()
      + '&ts=' + shareData.timestamp.toString()
      + '&' + shareData.shareJson
    let sign = await QQUtil.sign(signContent);

    shareData.shareJsonSign = sign
    const qqOpenApi = QQUtil.getQQOpenApi()
    if (!qqOpenApi.isQQInstalled()) {
      promptAction.showToast({message:"qq未安装"})
      return
    }
    qqOpenApi.share(2, shareData,QQUtil.appId.toString()).then((result: ShareResult) => {
      Logger.info('TAG', `qqOpenApi.share, result=${JSON.stringify(result)}`)
      switch (result.resultType) {
        case ShareResultType.Success: {
          promptAction.showToast({ message: "分享成功" })
        }
          break
        case ShareResultType.Cancel: {
          let msg: string = result.message ?? "用户取消分享"
          promptAction.showToast({ message: msg })
        }
          break
        case ShareResultType.Error: {
          let msg: string = result.message ?? "分享失败"
          promptAction.showToast({ message: msg })
        }
          break
      }
    })
      .catch((err: BusinessError) => {
        Logger.error("TAG", `error, code=${JSON.stringify(err.code)}, message=${JSON.stringify(err.message)}`)
      })
  }

  static getQQOpenApi(): IQQOpenApi {
    if (!QQUtil.qqOpenApi) {
      let openApiOption: OpenApiConfig = {
        forceEnableWeb: false,
        autoHandleAuthResult: true,
      }

      QQUtil.qqOpenApi =
        QQOpenApiFactory.createApi(QQUtil.appId, openApiOption)
    }
    return QQUtil.qqOpenApi

  }

  static async sign(shareJson: string): Promise<string> {

    let keyData = new Uint8Array(buffer.from('QQ加密appSecret', 'utf-8').buffer);
    let symKeyBlob: cryptoFramework.DataBlob = { data: keyData };
    let aesGenerator = cryptoFramework.createSymKeyGenerator('HMAC');
    let symKey = await aesGenerator.convertKey(symKeyBlob);
    let macAlgName = 'SHA1'; // 摘要算法名。
    let mac = cryptoFramework.createMac(macAlgName);
    await mac.init(symKey);
    // 数据量较少时,可以一次性执行update操作,将所有数据传入。该接口不对入参长度进行限制。
    await mac.update({ data: new Uint8Array(buffer.from(shareJson, 'utf-8').buffer) });
    let macResult = await mac.doFinal();
    let base64 = new util.Base64Helper();
    return base64.encodeToStringSync(macResult.data);
  }
}

export const qqShare = QQUtil.share

更多关于HarmonyOS鸿蒙Next中QQ分享功能,我这样分享过后,QQ那边显示分享失败是为什么,求助各位大佬的实战教程也可以访问 https://www.itying.com/category-93-b0.html

4 回复

AppSecret配置错误:

代码中keyData使用固定字符串’QQ加密appSecret’,实际开发需替换为QQ开放平台分配的真实AppSecret。密钥不匹配会导致签名校验失败。

签名算法实现差异:

你使用HMAC-SHA1算法,但需注意:

let aesGenerator = cryptoFramework.createSymKeyGenerator('HMAC'); // 需确认是否指定SHA1

let macAlgName = 'SHA1'; // 必须与QQ开放平台要求一致

需核对QQ SDK文档要求的签名算法,部分平台可能要求SHA256。

更多关于HarmonyOS鸿蒙Next中QQ分享功能,我这样分享过后,QQ那边显示分享失败是为什么,求助各位大佬的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


我已经解决了,这里还是需要使用AppKey来进行签名

import { CryptoJS } from '@ohos/crypto-js'
import {
  IQQOpenApi,
  OpenApiConfig,
  QQOpenApiFactory,
  ShareData,
  ShareResult,
  ShareResultType } from '@tencent/qq-open-sdk'
import { promptAction } from '@kit.ArkUI'
import { BusinessError } from '@kit.BasicServicesKit'
import { Logger } from 'accomponentitembase'

export class QQUtil {
  static appId = 111111111
  static AppKey = ''
  private static qqOpenApi: IQQOpenApi

  /**
   * 分享
   * @param title 标题
   * @param summary 内容
   * @param brief QQ信息列表显示的内容
   * @param imageUrl 图片链接
   * @param url 跳转链接
   */
  static share(title: string, summary: string, brief: string, imageUrl: string, url: string) {


    let content = new Object({
      msg_style: 0,
      title: title,
      summary: summary,
      brief: brief,
      url: url,
      picture_url: imageUrl
    })
    let shareData: ShareData = new ShareData()
    shareData.timestamp = Date.parse(new Date().toString()) / 1000
    shareData.nonce = Math.floor(Math.random() * 100000000 + 100)
    shareData.shareJson = JSON.stringify(content)
    let signContent = 'POSTconnect.qq.com/share?appid=' + QQUtil.appId.toString()
      + '&nonce=' + shareData.nonce.toString()
      + '&ts=' + shareData.timestamp.toString()
      + '&' + shareData.shareJson
      //这里的签名信息还是使用插件CryptoJS
    const hmac = CryptoJS.HmacSHA1(signContent, QQUtil.AppKey);
    let sign = hmac.toString(CryptoJS.enc.Base64);

    shareData.shareJsonSign = sign
    const qqOpenApi = QQUtil.getQQOpenApi()
    if (!qqOpenApi.isQQInstalled()) {
      promptAction.showToast({message:"qq未安装"})
      return
    }
    qqOpenApi.share(2, shareData).then((result: ShareResult) => {
      Logger.info('TAG', `qqOpenApi.share, result=${JSON.stringify(result)}`)
      switch (result.resultType) {
        case ShareResultType.Success: {
          promptAction.showToast({ message: "分享成功" })
        }
          break
        case ShareResultType.Cancel: {
          let msg: string = result.message ?? "用户取消分享"
          promptAction.showToast({ message: msg })
        }
          break
        case ShareResultType.Error: {
          let msg: string = result.message ?? "分享失败"
          promptAction.showToast({ message: msg })
        }
          break
      }
    })
      .catch((err: BusinessError) => {
        Logger.error("TAG", `error, code=${JSON.stringify(err.code)}, message=${JSON.stringify(err.message)}`)
      })
  }

  static getQQOpenApi(): IQQOpenApi {
    if (!QQUtil.qqOpenApi) {
      let openApiOption: OpenApiConfig = {
        forceEnableWeb: false,
        autoHandleAuthResult: true,
      }

      QQUtil.qqOpenApi =
        QQOpenApiFactory.createApi(QQUtil.appId, openApiOption)
    }
    return QQUtil.qqOpenApi

  }
}

export const qqShare = QQUtil.share

鸿蒙Next中QQ分享失败可能原因:

  1. SDK版本不兼容鸿蒙Next系统;
  2. 应用签名未在QQ开放平台正确配置;
  3. 鸿蒙Next权限管理限制分享操作;
  4. QQ客户端未适配鸿蒙Next新特性。

请检查QQ开放平台配置和鸿蒙SDK文档。

分享失败可能有以下几个原因:

  1. 签名计算错误:检查signContent的拼接格式是否符合QQ开放平台要求,特别是appidnoncetsshareJson的顺序和分隔符是否正确。确保appSecret是有效的密钥。

  2. 时间戳问题timestamp使用的是秒级时间戳,但Date.parse()返回的是毫秒,除以1000是正确的,但建议直接使用Math.floor(Date.now() / 1000)更简洁。

  3. 网络权限:确认应用已申请必要的网络权限(如ohos.permission.INTERNET),否则可能导致连接QQ服务器失败。

  4. QQ版本兼容性:确保用户安装的QQ版本支持OpenSDK功能,过旧版本可能无法处理分享请求。

  5. 参数格式:检查shareJson中的字段(如picture_urlurl)是否是有效的URL格式,无效链接会导致分享失败。

建议在catch块中输出详细的错误信息(如err.codeerr.message),以便进一步定位问题。

回到顶部