icssoa 5 місяців тому
батько
коміт
629d402a88

+ 1 - 1
.cursor/rules/cool.mdc

@@ -4,7 +4,7 @@ globs: *.uts,*.uvue
 alwaysApply: false
 ---
 
-# ts
+# ts | uts
 
 - 所有方法必须在被调用之前进行定义,避免出现“先调用后定义”的情况。
 - 当使用 {} 进行对象赋值时,必须显式声明类型,例如:{} as Data,确保类型安全与规范。

+ 4 - 1
.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"
+	}
 }

+ 2 - 2
README.md

@@ -40,8 +40,8 @@ Cool Unix 是一个高效的项目脚手架。它内置了 UI 组件库、Servic
 
 ```html
 <script setup lang="ts">
-	import { $t, t } from "@/uni_modules/cool-unix";
-	import { useUi } from "@/uni_modules/cool-unix";
+	import { $t, t } from "@/uni_modules/cool-ui";
+	import { useUi } from "@/uni_modules/cool-ui";
 
 	const ui = useUi();
 

+ 6 - 0
pages.json

@@ -504,6 +504,12 @@
 				},
 				{
 					"path": "other/router/query"
+				},
+				{
+					"path": "other/share",
+					"style": {
+						"navigationBarTitleText": "Share 分享"
+					}
 				}
 			]
 		},

+ 73 - 0
pages/demo/other/share.uvue

@@ -0,0 +1,73 @@
+<template>
+	<cl-page>
+		<view class="p-3">
+			<demo-item :label="t('分享文本')">
+				<cl-button @tap="shareText">{{ t("分享文本") }}</cl-button>
+			</demo-item>
+
+			<demo-item :label="t('分享图片')">
+				<cl-button @tap="shareImage">{{ t("分享图片") }}</cl-button>
+			</demo-item>
+
+			<demo-item :label="t('分享文件')">
+				<cl-button @tap="shareFile">{{ t("分享文件") }}</cl-button>
+			</demo-item>
+
+			<demo-item :label="t('分享链接')">
+				<cl-button @tap="shareLink">{{ t("分享链接") }}</cl-button>
+			</demo-item>
+		</view>
+	</cl-page>
+</template>
+
+<script lang="ts" setup>
+import { shareWithSystem } from "@/uni_modules/cool-share";
+import DemoItem from "../components/item.uvue";
+import { t } from "@/locale";
+
+function shareText() {
+	shareWithSystem({
+		type: "text",
+		title: "Cool Unix 是一个高效的项目脚手架",
+		summary: "",
+		success: () => {
+			console.log("success");
+		},
+		fail: (error) => {
+			console.log("fail", error);
+		}
+	});
+}
+
+function shareImage() {
+	shareWithSystem({
+		type: "image",
+		imageUrl: "https://cool-js.com/logo.png",
+		success: () => {
+			console.log("success");
+		}
+	});
+}
+
+function shareFile() {
+	shareWithSystem({
+		type: "file",
+		href: "https://show.cool-admin.com/用户导入模版.xlsx",
+		success: () => {
+			console.log("success");
+		}
+	});
+}
+
+function shareLink() {
+	shareWithSystem({
+		type: "link",
+		href: "https://cool-js.com/",
+		success: () => {
+			console.log("success");
+		}
+	});
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 5 - 0
pages/index/home.uvue

@@ -471,6 +471,11 @@ const data = computed<Item[]>(() => {
 					label: "Router",
 					icon: "compass-discover-line",
 					path: "/pages/demo/other/router/index"
+				},
+				{
+					label: "Share",
+					icon: "share-line",
+					path: "/pages/demo/other/share"
 				}
 			]
 		}

+ 11 - 0
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;
+}

+ 84 - 0
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"
+				}
+			}
+		}
+	}
+}

+ 25 - 0
uni_modules/cool-share/utssdk/app-android/AndroidManifest.xml

@@ -0,0 +1,25 @@
+<?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="uts.sdk.modules.coolShare">
+
+	<uses-permission android:name="android.permission.INTERNET" />
+	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+	<application>
+		<meta-data android:name="ScopedStorage" android:value="true" />
+
+		<provider
+			android:name="androidx.core.content.FileProvider"
+			android:authorities="${applicationId}.fileprovider"
+			android:exported="false"
+			android:grantUriPermissions="true"
+			tools:replace="android:authorities">
+			<meta-data
+				android:name="android.support.FILE_PROVIDER_PATHS"
+				android:resource="@xml/file_paths" />
+		</provider>
+	</application>
+</manifest>

+ 3 - 0
uni_modules/cool-share/utssdk/app-android/config.json

@@ -0,0 +1,3 @@
+{
+	"minSdkVersion": "21"
+}

+ 461 - 0
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);
+	}
+}

+ 17 - 0
uni_modules/cool-share/utssdk/app-android/res/xml/file_paths.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+	<!-- 外部存储路径 -->
+	<external-path name="external_files" path="." />
+
+	<!-- 外部缓存路径 -->
+	<external-cache-path name="external_cache" path="." />
+
+	<!-- 应用缓存路径(用于 uni.downloadFile 下载的临时文件) -->
+	<cache-path name="cache" path="." />
+
+	<!-- 应用内部文件路径 -->
+	<files-path name="files" path="." />
+
+	<!-- 根路径(谨慎使用) -->
+	<root-path name="root" path="." />
+</paths>

+ 14 - 0
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 ?? (() => {})
+	);
+}

+ 265 - 0
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);
+		});
+}

+ 9 - 0
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;
+};