文章配图:systemShare 的使用

页面预览

前言

ShareKit 是 HarmonyOS 的分享服务能力,支持应用间分享文本、图片、文件等数据。在「猫猫大作战」中,玩家完成一局游戏后可以分享战绩到微信、微博等社交平台,吸引更多朋友来挑战。

本文以「猫猫大作战」的战绩分享功能为锚点,讲解 systemShare 的完整使用方法,包括文本分享图片分享UniformDataObject 数据封装以及分享后的回调处理

提示:本系列不讲 ArkTS 基础语法与环境搭建。本篇是阶段五第 154 篇。

一、systemShare 基础用法

1.1 分享文本

import { systemShare } from '@kit.ShareKit';
import { uniformDataStruct } from '@kit.ArkData';

async function shareText(score: number, playerName: string): Promise<void> {
  const sharedData: uniformDataStruct.UniformDataObject = {
    value: {
      text: `我在「猫猫大作战」中获得了 ${score} 分!快来挑战我吧!🐱`,
      html: `<h3>猫猫大作战</h3><p>得分: <b>${score}</b></p><p>玩家: ${playerName}</p>`,
    },
    type: 'general.text',
  };

  await systemShare.share(sharedData);
}

1.2 参数说明

参数 类型 说明 示例
value.text string 纯文本内容 “我在猫猫大作战中获得了 2450 分!”
value.html string HTML 富文本(可选) <b>2450</b> 分
type string 统一类型标识符 (UTD) 'general.text''general.image'

提示:type 字段是 UTD(Uniform Type Descriptor),告诉系统分享数据的类型。常用类型:general.text(文本)、general.image(图片)、general.file(文件)。

二、 UniformDataObject 数据封装

2.1 数据封装方法

import { uniformDataStruct } from '@kit.ArkData';

// 文本分享
const textData: uniformDataStruct.UniformDataObject = {
  value: { text: '分享内容', html: '<b>富文本</b>' },
  type: 'general.text',
};

// 图片分享
const imageData: uniformDataStruct.UniformDataObject = {
  value: { image: pixelMap },
  type: 'general.image',
};

// 文件分享
const fileData: uniformDataStruct.UniformDataObject = {
  value: { fileUri: 'file://{sandboxPath}/score.png' },
  type: 'general.file',
};

2.2 数据类型的 UTD 对照

分享类型 UTD 标识 value 格式 目标应用
纯文本 general.text { text: string } 微信、短信
富文本 general.text { text, html } 微信、QQ
图片 general.image { image: PixelMap } 微博、朋友圈
文件 general.file { fileUri: string } 文件管理器
链接 general.url { url: string } 浏览器

三、游戏中分享战绩的完整实现

3.1 战绩分享按钮

// 游戏结束界面的分享按钮
@Builder
ShareButton(score: number, playerName: string) {
  Button({
    icon: $r('app.media.ic_share'),
    text: '分享战绩'
  })
  .width('80%').height(48)
  .fontSize(17).fontColor('#FFFFFF')
  .backgroundColor('#45B7D1')
  .borderRadius(24)
  .onClick(async () => {
    try {
      await shareGameResult(score, playerName);
      promptAction.showToast({ message: '分享成功!' });
    } catch (err) {
      console.error(`分享失败: ${err.message}`);
      promptAction.showToast({ message: '分享取消或失败' });
    }
  })
}

3.2 构造分享内容

async function shareGameResult(score: number, playerName: string): Promise<void> {
  // 构造分享文本
  const scoreText = score.toLocaleString('zh-CN');
  const shareContent = formatShareText(score, playerName);

  const sharedData: uniformDataStruct.UniformDataObject = {
    value: {
      text: shareContent.text,
      html: shareContent.html,
    },
    type: 'general.text',
  };

  await systemShare.share(sharedData);
}

function formatShareText(score: number, playerName: string) {
  const scoreText = score.toLocaleString('zh-CN');
  return {
    text: `🐱 我在「猫猫大作战」中获得 ${scoreText} 分!来挑战我的记录吧!下载地址: https://appgallery.huawei.com/cat-battle-war`,
    html: `
      <div style="text-align:center;padding:20px;">
        <h2>🐱 猫猫大作战</h2>
        <p style="font-size:24px;color:#E74C3C;">
          <b>${scoreText}</b> 分
        </p>
        <p>玩家: ${playerName}</p>
        <p style="font-size:14px;color:#95A5A6;">
          来挑战我的记录吧!
        </p>
      </div>
    `,
  };
}

3.3 分享回调处理

// systemShare.share() 返回的 Promise
// resolve = 用户选择了分享目标
// reject = 用户取消或分享失败

try {
  const result = await systemShare.share(sharedData);
  // 分享成功(用户选择了目标应用)
  console.info('分享成功', JSON.stringify(result));
  // 可以在这里触发分享成功统计
  analytics.recordEvent('share_success', { score });
} catch (err) {
  // 用户取消或在目标应用分享失败
  console.info(`分享取消: ${err.message}`);
  // 不视为错误,只记录取消
  analytics.recordEvent('share_cancel');
}

四、分享图片(截图)

4.1 截取游戏画面

import { image } from '@kit.ImageKit';

async function captureAndShare(): Promise<void> {
  // 1. 获取当前 UI 的 PixelMap(截图)
  const uiContext = this.getUIContext();
  const pixelMap = await uiContext.createPixelMap({
    width: 360,
    height: 640,
  });

  // 2. 编码为 JPEG
  const packer = image.createImagePacker();
  const buffer = await packer.packing(pixelMap, {
    format: 'image/jpeg',
    quality: 85,
  });
  packer.release();

  // 3. 保存到临时文件
  const context = getContext() as common.UIAbilityContext;
  const tempPath = `${context.tempDir}/share_score.jpg`;
  const file = fileIo.openSync(tempPath,
    fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY | fileIo.OpenMode.TRUNC);
  fileIo.writeSync(file.fd, buffer);
  fileIo.closeSync(file);

  // 4. 分享图片文件
  const sharedData: uniformDataStruct.UniformDataObject = {
    value: { fileUri: `file://${tempPath}` },
    type: 'general.file',
  };
  await systemShare.share(sharedData);
}

4.2 图片规��

图片类型 建议尺寸 格式 质量 文件大小
战绩分享截图 360×640 JPEG 85% ~100KB
邀请横幅 720×360 PNG - ~200KB
角色卡片 240×240 PNG - ~50KB

提示:分享图片文件大小建议不超过 1MB。过大的图片在社交平台加载慢,可能被压缩。

五、文件分享(战绩数据导出)

async function shareGameData(playerName: string, records: GameRecord[]): Promise<void> {
  // 1. 序列化战绩数据为 JSON
  const data = JSON.stringify({
    playerName,
    exportDate: new Date().toISOString(),
    records,
  }, null, 2);

  // 2. 写入临时文件
  const context = getContext() as common.UIAbilityContext;
  const filePath = `${context.tempDir}/game_data_${Date.now()}.json`;
  const file = fileIo.openSync(filePath,
    fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY | fileIo.OpenMode.TRUNC);
  fileIo.writeSync(file.fd, data);
  fileIo.closeSync(file);

  // 3. 分享文件
  const sharedData: uniformDataStruct.UniformDataObject = {
    value: { fileUri: `file://${filePath}` },
    type: 'general.file',
  };
  await systemShare.share(sharedData);
}

六、ShareKit vs 原生分享方案

维度 systemShare 原生 systemShare 自定义分享面板
集成复杂度 简单(3 行代码) 中等 复杂
目标应用 系统所有支持的应用 系统所有 手动指定
UI 一致性 系统原生界面 系统原生 需自定义
支持数据类型 文本/图片/文件 文本/URI 任意
推荐场景 通用分享 通用分享 品牌定制分享

七、分享最佳实践

7.1 分享内容策略

  1. 引人注目的开头:用 Emoji 🐱🏆 吸引注意
  2. 具体数字:得分要精确(2450 分 比"很高分"更吸引人)
  3. 行动号召:“来挑战我吧!” 引导好友下载
  4. 下载链接:附带应用市场下载地址
  5. 个性化:包含玩家名称,让好友知道是谁在邀请

7.2 性能考虑

// ✅ 分享操作应在用户点击后异步执行,避免阻塞 UI
Button('分享').onClick(async () => {
  // show loading
  this.isSharing = true;
  try {
    await shareGameResult(this.score, this.playerName);
  } finally {
    this.isSharing = false;
  }
})

// ✅ 大图片分享前压缩
async function compressForShare(pixelMap: PixelMap): Promise<ArrayBuffer> {
  const packer = image.createImagePacker();
  const buffer = await packer.packing(pixelMap, {
    format: 'image/jpeg',
    quality: 75,  // 适当降低质量减小文件
  });
  packer.release();
  return buffer;
}

八、错误排查

问题 可能原因 解决方法
分享界面未弹出 数据格式错误 检查 UniformDataObject 结构
分享后无响应 UTD 类型不匹配 确保 type 与实际 value 匹配
图片分享失败 文件路径不存在 检查 file:// 路径和文件权限
内容为空 value.text 未设 确保 text 字段有内容

九、权限与合规

// 分享不需要额外权限
// 但如果要分享图片,需要读取临时文件的权限
// 临时文件在 tempDir 中,应用自有权限可直接读写

// 隐私提示:分享内容中包含玩家名称,需在隐私政策中说明
const sharePrivacyNotice = `
  分享功能会包含您的游戏昵称和得分信息。
  这些信息仅用于本次分享,不会被我们收集。
`;

十、多语言分享

function formatShareByLocale(score: number, locale: string) {
  const scoreText = score.toLocaleString(locale === 'zh' ? 'zh-CN' : 'en-US');

  const templates: Record<string, { text: string; html: string }> = {
    'zh': {
      text: `🐱 我在「猫猫大作战」中获得 ${scoreText} 分!`,
      html: `<b>${scoreText}</b> 分`,
    },
    'en': {
      text: `🐱 I scored ${scoreText} in Cat Battle!`,
      html: `Score: <b>${scoreText}</b>`,
    },
  };

  return templates[locale] ?? templates['en'];
}

总结

ShareKit 通过 systemShare.share() 提供系统级分享能力,支持文本、图片、文件三种数据格式。核心要点:UniformDataObject 封装数据、 type 字段标识数据类型、 文本分享附带 HTML 增强展示、 图片先压缩再分享、 分享取消非异常、 包含下载链接传播应用

下一篇将深入 systemShare——SharedData 与 UTD 类型详解。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐