From 629d402a889861a57ac14689de349e5472892c28 Mon Sep 17 00:00:00 2001 From: icssoa <615206459@qq.com> Date: Thu, 30 Oct 2025 19:28:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20cool-share=20=E6=8F=92?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/cool.mdc | 2 +- .vscode/settings.json | 5 +- README.md | 4 +- pages.json | 6 + pages/demo/other/share.uvue | 73 +++ pages/index/home.uvue | 5 + uni_modules/cool-share/index.d.ts | 11 + uni_modules/cool-share/package.json | 84 ++++ .../utssdk/app-android/AndroidManifest.xml | 25 + .../cool-share/utssdk/app-android/config.json | 3 + .../cool-share/utssdk/app-android/index.uts | 461 ++++++++++++++++++ .../utssdk/app-android/res/xml/file_paths.xml | 17 + .../cool-share/utssdk/app-harmony/index.uts | 14 + .../cool-share/utssdk/app-harmony/share.ets | 265 ++++++++++ uni_modules/cool-share/utssdk/interface.uts | 9 + 15 files changed, 980 insertions(+), 4 deletions(-) create mode 100644 pages/demo/other/share.uvue create mode 100644 uni_modules/cool-share/index.d.ts create mode 100644 uni_modules/cool-share/package.json create mode 100644 uni_modules/cool-share/utssdk/app-android/AndroidManifest.xml create mode 100644 uni_modules/cool-share/utssdk/app-android/config.json create mode 100644 uni_modules/cool-share/utssdk/app-android/index.uts create mode 100644 uni_modules/cool-share/utssdk/app-android/res/xml/file_paths.xml create mode 100644 uni_modules/cool-share/utssdk/app-harmony/index.uts create mode 100644 uni_modules/cool-share/utssdk/app-harmony/share.ets create mode 100644 uni_modules/cool-share/utssdk/interface.uts diff --git a/.cursor/rules/cool.mdc b/.cursor/rules/cool.mdc index 86c0cc7..e36d179 100644 --- a/.cursor/rules/cool.mdc +++ b/.cursor/rules/cool.mdc @@ -4,7 +4,7 @@ globs: *.uts,*.uvue alwaysApply: false --- -# ts +# ts | uts - 所有方法必须在被调用之前进行定义,避免出现“先调用后定义”的情况。 - 当使用 {} 进行对象赋值时,必须显式声明类型,例如:{} as Data,确保类型安全与规范。 diff --git a/.vscode/settings.json b/.vscode/settings.json index 69fed09..12ecf0a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,5 +15,8 @@ "[ets]": { "editor.defaultFormatter": "NailyZero.vscode-naily-ets" }, - "scss.lint.unknownAtRules": "ignore" + "scss.lint.unknownAtRules": "ignore", + "[xml]": { + "editor.defaultFormatter": "redhat.vscode-xml" + } } diff --git a/README.md b/README.md index 359c10f..4120bd1 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,8 @@ Cool Unix 是一个高效的项目脚手架。它内置了 UI 组件库、Servic ```html + + diff --git a/pages/index/home.uvue b/pages/index/home.uvue index 7b72ef4..a4e69de 100644 --- a/pages/index/home.uvue +++ b/pages/index/home.uvue @@ -471,6 +471,11 @@ const data = computed(() => { label: "Router", icon: "compass-discover-line", path: "/pages/demo/other/router/index" + }, + { + label: "Share", + icon: "share-line", + path: "/pages/demo/other/share" } ] } diff --git a/uni_modules/cool-share/index.d.ts b/uni_modules/cool-share/index.d.ts new file mode 100644 index 0000000..ef63c55 --- /dev/null +++ b/uni_modules/cool-share/index.d.ts @@ -0,0 +1,11 @@ +declare module "@/uni_modules/cool-share" { + export function shareWithSystem(options: { + type: "text" | "image" | "file" | "link" | "video" | "audio"; + title?: string; + summary?: string; + href?: string; + imageUrl?: string; + success?: () => void; + fail?: (error: string) => void; + }): void; +} diff --git a/uni_modules/cool-share/package.json b/uni_modules/cool-share/package.json new file mode 100644 index 0000000..5e917f3 --- /dev/null +++ b/uni_modules/cool-share/package.json @@ -0,0 +1,84 @@ +{ + "id": "cool-share", + "displayName": "cool-share", + "version": "1.0.0", + "description": "cool-share", + "keywords": [ + "cool-share", + "share", + "系统分享" + ], + "repository": "", + "engines": { + "HBuilderX": "^4.75" + }, + "dcloudext": { + "type": "uts", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-android": "u", + "app-ios": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} diff --git a/uni_modules/cool-share/utssdk/app-android/AndroidManifest.xml b/uni_modules/cool-share/utssdk/app-android/AndroidManifest.xml new file mode 100644 index 0000000..494ebb7 --- /dev/null +++ b/uni_modules/cool-share/utssdk/app-android/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/uni_modules/cool-share/utssdk/app-android/config.json b/uni_modules/cool-share/utssdk/app-android/config.json new file mode 100644 index 0000000..f3189d0 --- /dev/null +++ b/uni_modules/cool-share/utssdk/app-android/config.json @@ -0,0 +1,3 @@ +{ + "minSdkVersion": "21" +} diff --git a/uni_modules/cool-share/utssdk/app-android/index.uts b/uni_modules/cool-share/utssdk/app-android/index.uts new file mode 100644 index 0000000..bf43228 --- /dev/null +++ b/uni_modules/cool-share/utssdk/app-android/index.uts @@ -0,0 +1,461 @@ +import Intent from "android.content.Intent"; +import Uri from "android.net.Uri"; +import Context from "android.content.Context"; +import File from "java.io.File"; +import FileProvider from "androidx.core.content.FileProvider"; +import { ShareWithSystemOptions } from "../interface.uts"; + +/** + * 分享类型枚举 + */ +const ShareType = { + TEXT: "text", // 纯文本分享 + IMAGE: "image", // 图片分享 + VIDEO: "video", // 视频分享 + AUDIO: "audio", // 音频分享 + FILE: "file", // 文件分享 + LINK: "link" // 链接分享 +}; + +/** + * MIME 类型映射 + */ +const MimeTypes = { + IMAGE: "image/*", + VIDEO: "video/*", + AUDIO: "audio/*", + TEXT: "text/plain", + PDF: "application/pdf", + WORD: "application/msword", + EXCEL: "application/vnd.ms-excel", + PPT: "application/vnd.ms-powerpoint", + ZIP: "application/zip", + DEFAULT: "*/*" +}; + +/** + * 判断是否为网络 URL + * @param url 地址 + * @returns 是否为网络 URL + */ +function isNetworkUrl(url: string): boolean { + return url.startsWith("http://") || url.startsWith("https://"); +} + +/** + * 根据文件路径获取 File 对象 + * 按优先级尝试多种路径解析方式 + * @param filePath 文件路径 + * @returns File 对象或 null + */ +function getFileFromPath(filePath: string): File | null { + // 1. 尝试直接路径 + let file = new File(filePath); + if (file.exists()) { + return file; + } + + // 2. 尝试资源路径 + file = new File(UTSAndroid.getResourcePath(filePath)); + if (file.exists()) { + return file; + } + + // 3. 尝试绝对路径转换 + file = new File(UTSAndroid.convert2AbsFullPath(filePath)); + if (file.exists()) { + return file; + } + + return null; +} + +/** + * 根据文件扩展名获取 MIME 类型 + * @param filePath 文件路径 + * @param defaultType 默认类型 + * @returns MIME 类型字符串 + */ +function getMimeTypeByPath(filePath: string, defaultType: string): string { + const ext = filePath.split(".").pop()?.toLowerCase() ?? ""; + + if (ext == "") { + return defaultType; + } + + // 常见文件类型映射 + const mimeMap = { + // 文档类型 + pdf: MimeTypes["PDF"], + doc: MimeTypes["WORD"], + docx: MimeTypes["WORD"], + xls: MimeTypes["EXCEL"], + xlsx: MimeTypes["EXCEL"], + ppt: MimeTypes["PPT"], + pptx: MimeTypes["PPT"], + // 压缩包类型 + zip: MimeTypes["ZIP"], + rar: "application/x-rar-compressed", + "7z": "application/x-7z-compressed", + tar: "application/x-tar", + gz: "application/gzip" + }; + + return (mimeMap[ext] as string) ?? defaultType; +} + +/** + * 下载网络文件到本地缓存 + * @param url 网络地址 + * @param success 成功回调,返回本地文件路径 + * @param fail 失败回调 + */ +function downloadNetworkFile( + url: string, + success: (localPath: string) => void, + fail: (error: string) => void +): void { + uni.downloadFile({ + url: url, + success: (res) => { + if (res.statusCode == 200) { + success(res.tempFilePath); + } else { + fail("下载失败,状态码: " + res.statusCode); + } + }, + fail: (err) => { + fail("下载失败: " + (err.errMsg ?? "未知错误")); + } + }); +} + +/** + * 创建文件 Uri + * @param filePath 文件路径(支持本地路径和网络 URL) + * @param success 成功回调 + * @param fail 失败回调 + */ +function createFileUriAsync( + filePath: string, + success: (uri: Uri) => void, + fail: (error: string) => void +): void { + // 创建文件Uri,支持网络和本地文件。网络文件先下载到本地缓存,再获取Uri。 + const handleFileToUri = (localPath: string) => { + const file = getFileFromPath(localPath); + if (file == null) { + fail(`文件不存在: ${localPath}`); + return; + } + const context = UTSAndroid.getAppContext(); + if (context == null) { + fail("无法获取App Context"); + return; + } + const authority = context.getPackageName() + ".fileprovider"; + const uri = FileProvider.getUriForFile(context, authority, file); + success(uri); + }; + + if (isNetworkUrl(filePath)) { + // 网络路径需先下载,下载完成后处理 + downloadNetworkFile(filePath, handleFileToUri, fail); + } else { + // 本地文件直接处理 + handleFileToUri(filePath); + } +} + +/** + * 创建图片分享 Intent(异步) + * @param imageUrl 图片路径(支持本地路径和网络 URL) + * @param title 分享标题 + * @param success 成功回调 + * @param fail 失败回调 + */ +function createImageShareIntent( + imageUrl: string, + title: string, + success: (intent: Intent) => void, + fail: (error: string) => void +): void { + if (imageUrl == "") { + fail("图片路径不能为空"); + return; + } + + createFileUriAsync( + imageUrl, + (uri: Uri) => { + const intent = new Intent(Intent.ACTION_SEND); + intent.setType(MimeTypes["IMAGE"] as string); + intent.putExtra(Intent.EXTRA_STREAM, uri); + intent.putExtra(Intent.EXTRA_TITLE, title); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + success(intent); + }, + (error: string) => { + fail(error); + } + ); +} + +/** + * 创建视频分享 Intent(异步) + * @param videoUrl 视频路径(支持本地路径和网络 URL) + * @param title 分享标题 + * @param success 成功回调 + * @param fail 失败回调 + */ +function createVideoShareIntent( + videoUrl: string, + title: string, + success: (intent: Intent) => void, + fail: (error: string) => void +): void { + if (videoUrl == "") { + fail("视频路径不能为空"); + return; + } + + createFileUriAsync( + videoUrl, + (uri: Uri) => { + const intent = new Intent(Intent.ACTION_SEND); + intent.setType(MimeTypes["VIDEO"] as string); + intent.putExtra(Intent.EXTRA_STREAM, uri); + intent.putExtra(Intent.EXTRA_TITLE, title); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + success(intent); + }, + (error: string) => { + fail(error); + } + ); +} + +/** + * 创建音频分享 Intent(异步) + * @param audioUrl 音频路径(支持本地路径和网络 URL) + * @param title 分享标题 + * @param success 成功回调 + * @param fail 失败回调 + */ +function createAudioShareIntent( + audioUrl: string, + title: string, + success: (intent: Intent) => void, + fail: (error: string) => void +): void { + if (audioUrl == "") { + fail("音频路径不能为空"); + return; + } + + createFileUriAsync( + audioUrl, + (uri: Uri) => { + const intent = new Intent(Intent.ACTION_SEND); + intent.setType(MimeTypes["AUDIO"] as string); + intent.putExtra(Intent.EXTRA_STREAM, uri); + intent.putExtra(Intent.EXTRA_TITLE, title); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + success(intent); + }, + (error: string) => { + fail(error); + } + ); +} + +/** + * 创建文件分享 Intent(异步) + * @param filePath 文件路径(支持本地路径和网络 URL) + * @param title 分享标题 + * @param success 成功回调 + * @param fail 失败回调 + */ +function createFileShareIntent( + filePath: string, + title: string, + success: (intent: Intent) => void, + fail: (error: string) => void +): void { + if (filePath == "") { + fail("文件路径不能为空"); + return; + } + + createFileUriAsync( + filePath, + (uri: Uri) => { + // 根据文件扩展名确定 MIME 类型 + const mimeType = getMimeTypeByPath(filePath, MimeTypes["DEFAULT"] as string); + + const intent = new Intent(Intent.ACTION_SEND); + intent.setType(mimeType); + intent.putExtra(Intent.EXTRA_STREAM, uri); + intent.putExtra(Intent.EXTRA_TITLE, title); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + success(intent); + }, + (error: string) => { + fail(error); + } + ); +} + +/** + * 创建链接分享 Intent + * @param href 链接地址 + * @param title 分享标题 + * @param summary 分享描述 + * @param success 成功回调 + * @param fail 失败回调 + */ +function createLinkShareIntent( + href: string, + title: string, + summary: string, + success: (intent: Intent) => void, + fail: (error: string) => void +): void { + if (href == "") { + fail("链接地址不能为空"); + return; + } + + // 组合分享内容:标题 + 描述 + 链接 + let content = ""; + if (title != "") { + content = title; + } + if (summary != "") { + content = content == "" ? summary : content + "\n" + summary; + } + if (href != "") { + content = content == "" ? href : content + "\n" + href; + } + + const intent = new Intent(Intent.ACTION_SEND); + intent.setType(MimeTypes["TEXT"] as string); + intent.putExtra(Intent.EXTRA_TEXT, content); + + success(intent); +} + +/** + * 创建文本分享 Intent + * @param title 分享标题 + * @param summary 分享描述 + * @param href 附加链接(可选) + * @param success 成功回调 + */ +function createTextShareIntent( + title: string, + summary: string, + href: string, + success: (intent: Intent) => void +): void { + // 组合分享内容 + let content = ""; + if (title != "") { + content = title; + } + if (summary != "") { + content = content == "" ? summary : content + "\n" + summary; + } + if (href != "") { + content = content == "" ? href : content + "\n" + href; + } + + // 如果内容为空,使用默认文本 + if (content == "") { + content = "分享内容"; + } + + const intent = new Intent(Intent.ACTION_SEND); + intent.setType(MimeTypes["TEXT"] as string); + intent.putExtra(Intent.EXTRA_TEXT, content); + + success(intent); +} + +/** + * 启动分享 Activity + * @param intent 分享 Intent + * @param title 选择器标题 + * @param success 成功回调 + * @param fail 失败回调 + */ +function startShareActivity( + intent: Intent, + title: string, + success: () => void, + fail: (error: string) => void +): void { + const chooserTitle = title != "" ? title : "选择分享方式"; + const chooser = Intent.createChooser(intent, chooserTitle); + + try { + UTSAndroid.getUniActivity()!.startActivity(chooser); + success(); + } catch (e: Exception) { + const errorMsg = e.message ?? "分享失败"; + fail(errorMsg); + } +} + +/** + * 系统分享功能 + * @param options 分享参数 + * @param options.type 分享类型: text(文本) | image(图片) | video(视频) | audio(音频) | file(文件) | link(链接) + * @param options.title 分享标题 + * @param options.summary 分享描述/内容 + * @param options.href 链接地址或文件路径 + * @param options.imageUrl 图片/视频/音频路径(支持本地路径和网络 URL) + * @param options.success 成功回调 + * @param options.fail 失败回调 + */ +export function shareWithSystem(options: ShareWithSystemOptions): void { + const type = options.type; + const title = options.title ?? ""; + const summary = options.summary ?? ""; + const href = options.href ?? ""; + const imageUrl = options.imageUrl ?? ""; + + // 成功和失败回调 + const onSuccess = (intent: Intent) => { + startShareActivity( + intent, + title, + () => { + options.success?.(); + }, + (error: string) => { + options.fail?.(error); + } + ); + }; + + const onFail = (error: string) => { + options.fail?.(error); + }; + + // 根据分享类型创建对应的 Intent + if (type == ShareType["IMAGE"]) { + createImageShareIntent(imageUrl, title, onSuccess, onFail); + } else if (type == ShareType["VIDEO"]) { + createVideoShareIntent(imageUrl, title, onSuccess, onFail); + } else if (type == ShareType["AUDIO"]) { + createAudioShareIntent(imageUrl, title, onSuccess, onFail); + } else if (type == ShareType["FILE"]) { + createFileShareIntent(href, title, onSuccess, onFail); + } else if (type == ShareType["LINK"]) { + createLinkShareIntent(href, title, summary, onSuccess, onFail); + } else { + // 默认为文本分享 + createTextShareIntent(title, summary, href, onSuccess); + } +} diff --git a/uni_modules/cool-share/utssdk/app-android/res/xml/file_paths.xml b/uni_modules/cool-share/utssdk/app-android/res/xml/file_paths.xml new file mode 100644 index 0000000..ff3705f --- /dev/null +++ b/uni_modules/cool-share/utssdk/app-android/res/xml/file_paths.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/uni_modules/cool-share/utssdk/app-harmony/index.uts b/uni_modules/cool-share/utssdk/app-harmony/index.uts new file mode 100644 index 0000000..aa68117 --- /dev/null +++ b/uni_modules/cool-share/utssdk/app-harmony/index.uts @@ -0,0 +1,14 @@ +import { ShareWithSystemOptions } from "../interface.uts"; +import { share } from "./share.ets"; + +export function shareWithSystem(options: ShareWithSystemOptions) { + share( + options.type, + options.title ?? "", + options.summary ?? "", + options.href ?? "", + options.imageUrl ?? "", + options.success ?? (() => {}), + options.fail ?? (() => {}) + ); +} diff --git a/uni_modules/cool-share/utssdk/app-harmony/share.ets b/uni_modules/cool-share/utssdk/app-harmony/share.ets new file mode 100644 index 0000000..1bc2745 --- /dev/null +++ b/uni_modules/cool-share/utssdk/app-harmony/share.ets @@ -0,0 +1,265 @@ +import { UTSHarmony } from '@dcloudio/uni-app-x-runtime'; +import { systemShare } from '@kit.ShareKit'; +import { uniformTypeDescriptor as utd } from '@kit.ArkData'; +import { common } from '@kit.AbilityKit'; +import { fileUri } from '@kit.CoreFileKit'; +import { BusinessError } from '@kit.BasicServicesKit'; + +/** + * 分享类型枚举 + */ +enum ShareType { + TEXT = "text", // 纯文本分享 + IMAGE = "image", // 图片分享 + VIDEO = "video", // 视频分享 + AUDIO = "audio", // 音频分享 + FILE = "file", // 文件分享 + LINK = "link" // 链接分享 +} + +/** + * 根据文件路径获取统一数据类型标识符 + * @param filePath 文件路径 + * @param defaultType 默认数据类型 + * @returns 统一数据类型标识符 + */ +function getUtdTypeByPath(filePath: string, defaultType: string): string { + const ext = filePath?.split('.')?.pop()?.toLowerCase() ?? ''; + if (ext === '') { + return defaultType; + } + return utd.getUniformDataTypeByFilenameExtension('.' + ext, defaultType); +} + +/** + * 创建图片分享数据 + * @param imageUrl 图片路径(支持本地路径和网络 URL) + * @param title 分享标题 + * @param summary 分享描述 + * @returns 分享数据对象 + */ +function createImageShareData(imageUrl: string, title: string, summary: string): systemShare.SharedData | null { + if (imageUrl === '') { + return null; + } + + const filePath = UTSHarmony.getResourcePath(imageUrl); + const utdTypeId = getUtdTypeByPath(filePath, utd.UniformDataType.IMAGE); + + return new systemShare.SharedData({ + utd: utdTypeId, + uri: fileUri.getUriFromPath(filePath), + title: title, + description: summary, + }); +} + +/** + * 创建视频分享数据 + * @param videoUrl 视频路径(支持本地路径和网络 URL) + * @param title 分享标题 + * @param summary 分享描述 + * @returns 分享数据对象 + */ +function createVideoShareData(videoUrl: string, title: string, summary: string): systemShare.SharedData | null { + if (videoUrl === '') { + return null; + } + + const filePath = UTSHarmony.getResourcePath(videoUrl); + const utdTypeId = getUtdTypeByPath(filePath, utd.UniformDataType.VIDEO); + + return new systemShare.SharedData({ + utd: utdTypeId, + uri: fileUri.getUriFromPath(filePath), + title: title, + description: summary, + }); +} + +/** + * 创建音频分享数据 + * @param audioUrl 音频路径(支持本地路径和网络 URL) + * @param title 分享标题 + * @param summary 分享描述 + * @returns 分享数据对象 + */ +function createAudioShareData(audioUrl: string, title: string, summary: string): systemShare.SharedData | null { + if (audioUrl === '') { + return null; + } + + const filePath = UTSHarmony.getResourcePath(audioUrl); + const utdTypeId = getUtdTypeByPath(filePath, utd.UniformDataType.AUDIO); + + return new systemShare.SharedData({ + utd: utdTypeId, + uri: fileUri.getUriFromPath(filePath), + title: title, + description: summary, + }); +} + +/** + * 创建文件分享数据 + * @param filePath 文件路径(支持本地路径和网络 URL) + * @param title 分享标题 + * @param summary 分享描述 + * @returns 分享数据对象 + */ +function createFileShareData(filePath: string, title: string, summary: string): systemShare.SharedData | null { + if (filePath === '') { + return null; + } + + const resourcePath = UTSHarmony.getResourcePath(filePath); + const ext = resourcePath?.split('.')?.pop()?.toLowerCase() ?? ''; + + // 根据文件扩展名确定数据类型 + let utdType = utd.UniformDataType.FILE; + let utdTypeId = ''; + + // 支持常见的文件类型 + switch (ext) { + case 'zip': + case 'rar': + case '7z': + case 'tar': + case 'gz': + utdType = utd.UniformDataType.ARCHIVE; + break; + case 'pdf': + utdType = utd.UniformDataType.PDF; + break; + case 'doc': + case 'docx': + utdType = utd.UniformDataType.WORD_DOC; + break; + case 'xls': + case 'xlsx': + utdType = utd.UniformDataType.EXCEL; + break; + case 'ppt': + case 'pptx': + utdType = utd.UniformDataType.PPT; + break; + default: + utdType = utd.UniformDataType.FILE; + break; + } + + utdTypeId = utd.getUniformDataTypeByFilenameExtension('.' + ext, utdType); + + return new systemShare.SharedData({ + utd: utdTypeId, + uri: fileUri.getUriFromPath(resourcePath), + title: title, + description: summary, + }); +} + +/** + * 创建链接分享数据 + * @param href 链接地址 + * @param title 分享标题 + * @param summary 分享描述 + * @returns 分享数据对象 + */ +function createLinkShareData(href: string, title: string, summary: string): systemShare.SharedData { + return new systemShare.SharedData({ + utd: utd.UniformDataType.HYPERLINK, + title: title, + content: href, + description: summary + }); +} + +/** + * 创建文本分享数据 + * @param title 分享标题 + * @param summary 分享内容 + * @returns 分享数据对象 + */ +function createTextShareData(title: string, summary: string): systemShare.SharedData { + return new systemShare.SharedData({ + utd: utd.UniformDataType.TEXT, + title: title, + content: summary + }); +} + +/** + * 系统分享功能 + * @param options 分享参数 + * @param options.type 分享类型: text(文本) | image(图片) | video(视频) | audio(音频) | file(文件) | link(链接) + * @param options.title 分享标题 + * @param options.summary 分享描述/内容 + * @param options.href 链接地址或文件路径 + * @param options.imageUrl 图片/视频/音频路径(支持本地路径和网络 URL) + * @param options.success 成功回调 + * @param options.fail 失败回调 + */ +export function share(type: string, title: string, summary: string, href: string, imageUrl: string, success: () => void, fail: (error: string) => void): void { + // 获取UI上下文 + const uiContext: UIContext = UTSHarmony.getCurrentWindow()?.getUIContext(); + const context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext; + + // 根据分享类型创建分享数据 + let shareData: systemShare.SharedData | null = null; + let errorMsg = ''; + + switch (type) { + case ShareType.IMAGE: + shareData = createImageShareData(imageUrl, title, summary); + errorMsg = '图片路径不能为空'; + break; + + case ShareType.VIDEO: + shareData = createVideoShareData(imageUrl, title, summary); + errorMsg = '视频路径不能为空'; + break; + + case ShareType.AUDIO: + shareData = createAudioShareData(imageUrl, title, summary); + errorMsg = '音频路径不能为空'; + break; + + case ShareType.FILE: + shareData = createFileShareData(href, title, summary); + errorMsg = '文件路径不能为空'; + break; + + case ShareType.LINK: + shareData = createLinkShareData(href, title, summary); + break; + + default: + // 默认为文本分享 + shareData = createTextShareData(title, summary); + break; + } + + // 验证分享数据 + if (shareData === null) { + fail(errorMsg); + return; + } + + // 创建分享控制器 + const controller: systemShare.ShareController = new systemShare.ShareController(shareData); + + // 显示分享面板,配置分享选项 + controller.show(context, { + selectionMode: systemShare.SelectionMode.SINGLE, // 单选模式 + previewMode: systemShare.SharePreviewMode.DEFAULT, // 默认预览模式 + }) + .then(() => { + // 分享成功 + success(); + }) + .catch((error: BusinessError) => { + // 分享失败,返回错误信息 + const errorMessage = error?.message ?? '分享失败'; + fail(errorMessage); + }); +} \ No newline at end of file diff --git a/uni_modules/cool-share/utssdk/interface.uts b/uni_modules/cool-share/utssdk/interface.uts new file mode 100644 index 0000000..15cfd4a --- /dev/null +++ b/uni_modules/cool-share/utssdk/interface.uts @@ -0,0 +1,9 @@ +export type ShareWithSystemOptions = { + type: string; + title?: string; + summary?: string; + href?: string; + imageUrl?: string; + success?: () => void; + fail?: (error: string) => void; +};