Procházet zdrojové kódy

添加 cool-share 系统分享插件

icssoa před 5 měsíci
rodič
revize
1dc706654e

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
 	"name": "cool-unix",
-	"version": "8.0.29",
+	"version": "8.0.30",
 	"license": "MIT",
 	"scripts": {
 		"build-ui": "node ./uni_modules/cool-ui/scripts/generate-types.js",

+ 4 - 4
pages/demo/other/share.uvue

@@ -29,7 +29,7 @@ function shareText() {
 	shareWithSystem({
 		type: "text",
 		title: "Cool Unix 是一个高效的项目脚手架",
-		summary: "",
+		summary: "Cool Unix 是一个高效的项目脚手架",
 		success: () => {
 			console.log("success");
 		},
@@ -42,7 +42,7 @@ function shareText() {
 function shareImage() {
 	shareWithSystem({
 		type: "image",
-		imageUrl: "https://cool-js.com/logo.png",
+		url: "https://cool-js.com/logo.png",
 		success: () => {
 			console.log("success");
 		}
@@ -52,7 +52,7 @@ function shareImage() {
 function shareFile() {
 	shareWithSystem({
 		type: "file",
-		href: "https://show.cool-admin.com/用户导入模版.xlsx",
+		url: "https://show.cool-admin.com/用户导入模版.xlsx",
 		success: () => {
 			console.log("success");
 		}
@@ -62,7 +62,7 @@ function shareFile() {
 function shareLink() {
 	shareWithSystem({
 		type: "link",
-		href: "https://cool-js.com/",
+		url: "https://cool-js.com/",
 		success: () => {
 			console.log("success");
 		}

+ 1 - 2
uni_modules/cool-share/index.d.ts

@@ -3,8 +3,7 @@ declare module "@/uni_modules/cool-share" {
 		type: "text" | "image" | "file" | "link" | "video" | "audio";
 		title?: string;
 		summary?: string;
-		href?: string;
-		imageUrl?: string;
+		url?: string;
 		success?: () => void;
 		fail?: (error: string) => void;
 	}): void;

+ 29 - 31
uni_modules/cool-share/utssdk/app-android/index.uts

@@ -169,24 +169,24 @@ function createFileUriAsync(
 
 /**
  * 创建图片分享 Intent(异步)
- * @param imageUrl 图片路径(支持本地路径和网络 URL)
+ * @param url 图片路径(支持本地路径和网络 URL)
  * @param title 分享标题
  * @param success 成功回调
  * @param fail 失败回调
  */
 function createImageShareIntent(
-	imageUrl: string,
+	url: string,
 	title: string,
 	success: (intent: Intent) => void,
 	fail: (error: string) => void
 ): void {
-	if (imageUrl == "") {
+	if (url == "") {
 		fail("图片路径不能为空");
 		return;
 	}
 
 	createFileUriAsync(
-		imageUrl,
+		url,
 		(uri: Uri) => {
 			const intent = new Intent(Intent.ACTION_SEND);
 			intent.setType(MimeTypes["IMAGE"] as string);
@@ -203,24 +203,24 @@ function createImageShareIntent(
 
 /**
  * 创建视频分享 Intent(异步)
- * @param videoUrl 视频路径(支持本地路径和网络 URL)
+ * @param url 视频路径(支持本地路径和网络 URL)
  * @param title 分享标题
  * @param success 成功回调
  * @param fail 失败回调
  */
 function createVideoShareIntent(
-	videoUrl: string,
+	url: string,
 	title: string,
 	success: (intent: Intent) => void,
 	fail: (error: string) => void
 ): void {
-	if (videoUrl == "") {
+	if (url == "") {
 		fail("视频路径不能为空");
 		return;
 	}
 
 	createFileUriAsync(
-		videoUrl,
+		url,
 		(uri: Uri) => {
 			const intent = new Intent(Intent.ACTION_SEND);
 			intent.setType(MimeTypes["VIDEO"] as string);
@@ -237,24 +237,24 @@ function createVideoShareIntent(
 
 /**
  * 创建音频分享 Intent(异步)
- * @param audioUrl 音频路径(支持本地路径和网络 URL)
+ * @param url 音频路径(支持本地路径和网络 URL)
  * @param title 分享标题
  * @param success 成功回调
  * @param fail 失败回调
  */
 function createAudioShareIntent(
-	audioUrl: string,
+	url: string,
 	title: string,
 	success: (intent: Intent) => void,
 	fail: (error: string) => void
 ): void {
-	if (audioUrl == "") {
+	if (url == "") {
 		fail("音频路径不能为空");
 		return;
 	}
 
 	createFileUriAsync(
-		audioUrl,
+		url,
 		(uri: Uri) => {
 			const intent = new Intent(Intent.ACTION_SEND);
 			intent.setType(MimeTypes["AUDIO"] as string);
@@ -308,20 +308,20 @@ function createFileShareIntent(
 
 /**
  * 创建链接分享 Intent
- * @param href 链接地址
+ * @param url 链接地址
  * @param title 分享标题
  * @param summary 分享描述
  * @param success 成功回调
  * @param fail 失败回调
  */
 function createLinkShareIntent(
-	href: string,
+	url: string,
 	title: string,
 	summary: string,
 	success: (intent: Intent) => void,
 	fail: (error: string) => void
 ): void {
-	if (href == "") {
+	if (url == "") {
 		fail("链接地址不能为空");
 		return;
 	}
@@ -334,8 +334,8 @@ function createLinkShareIntent(
 	if (summary != "") {
 		content = content == "" ? summary : content + "\n" + summary;
 	}
-	if (href != "") {
-		content = content == "" ? href : content + "\n" + href;
+	if (url != "") {
+		content = content == "" ? url : content + "\n" + url;
 	}
 
 	const intent = new Intent(Intent.ACTION_SEND);
@@ -349,13 +349,13 @@ function createLinkShareIntent(
  * 创建文本分享 Intent
  * @param title 分享标题
  * @param summary 分享描述
- * @param href 附加链接(可选)
+ * @param url 附加链接(可选)
  * @param success 成功回调
  */
 function createTextShareIntent(
 	title: string,
 	summary: string,
-	href: string,
+	url: string,
 	success: (intent: Intent) => void
 ): void {
 	// 组合分享内容
@@ -366,8 +366,8 @@ function createTextShareIntent(
 	if (summary != "") {
 		content = content == "" ? summary : content + "\n" + summary;
 	}
-	if (href != "") {
-		content = content == "" ? href : content + "\n" + href;
+	if (url != "") {
+		content = content == "" ? url : content + "\n" + url;
 	}
 
 	// 如果内容为空,使用默认文本
@@ -413,8 +413,7 @@ function startShareActivity(
  * @param options.type 分享类型: text(文本) | image(图片) | video(视频) | audio(音频) | file(文件) | link(链接)
  * @param options.title 分享标题
  * @param options.summary 分享描述/内容
- * @param options.href 链接地址或文件路径
- * @param options.imageUrl 图片/视频/音频路径(支持本地路径和网络 URL)
+ * @param options.url 资源路径(图片/视频/音频/文件路径或链接地址,支持本地路径和网络 URL)
  * @param options.success 成功回调
  * @param options.fail 失败回调
  */
@@ -422,8 +421,7 @@ 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 url = options.url ?? "";
 
 	// 成功和失败回调
 	const onSuccess = (intent: Intent) => {
@@ -445,17 +443,17 @@ export function shareWithSystem(options: ShareWithSystemOptions): void {
 
 	// 根据分享类型创建对应的 Intent
 	if (type == ShareType["IMAGE"]) {
-		createImageShareIntent(imageUrl, title, onSuccess, onFail);
+		createImageShareIntent(url, title, onSuccess, onFail);
 	} else if (type == ShareType["VIDEO"]) {
-		createVideoShareIntent(imageUrl, title, onSuccess, onFail);
+		createVideoShareIntent(url, title, onSuccess, onFail);
 	} else if (type == ShareType["AUDIO"]) {
-		createAudioShareIntent(imageUrl, title, onSuccess, onFail);
+		createAudioShareIntent(url, title, onSuccess, onFail);
 	} else if (type == ShareType["FILE"]) {
-		createFileShareIntent(href, title, onSuccess, onFail);
+		createFileShareIntent(url, title, onSuccess, onFail);
 	} else if (type == ShareType["LINK"]) {
-		createLinkShareIntent(href, title, summary, onSuccess, onFail);
+		createLinkShareIntent(url, title, summary, onSuccess, onFail);
 	} else {
 		// 默认为文本分享
-		createTextShareIntent(title, summary, href, onSuccess);
+		createTextShareIntent(title, summary, url, onSuccess);
 	}
 }

+ 1 - 2
uni_modules/cool-share/utssdk/app-harmony/index.uts

@@ -6,8 +6,7 @@ export function shareWithSystem(options: ShareWithSystemOptions) {
 		options.type,
 		options.title ?? "",
 		options.summary ?? "",
-		options.href ?? "",
-		options.imageUrl ?? "",
+		options.url ?? "",
 		options.success ?? (() => {}),
 		options.fail ?? (() => {})
 	);

+ 23 - 23
uni_modules/cool-share/utssdk/app-harmony/share.ets

@@ -33,17 +33,17 @@ function getUtdTypeByPath(filePath: string, defaultType: string): string {
 
 /**
  * 创建图片分享数据
- * @param imageUrl 图片路径(支持本地路径和网络 URL)
+ * @param url 图片路径(支持本地路径和网络 URL)
  * @param title 分享标题
  * @param summary 分享描述
  * @returns 分享数据对象
  */
-function createImageShareData(imageUrl: string, title: string, summary: string): systemShare.SharedData | null {
-	if (imageUrl === '') {
+function createImageShareData(url: string, title: string, summary: string): systemShare.SharedData | null {
+	if (url === '') {
 		return null;
 	}
 
-	const filePath = UTSHarmony.getResourcePath(imageUrl);
+	const filePath = UTSHarmony.getResourcePath(url);
 	const utdTypeId = getUtdTypeByPath(filePath, utd.UniformDataType.IMAGE);
 
 	return new systemShare.SharedData({
@@ -56,17 +56,17 @@ function createImageShareData(imageUrl: string, title: string, summary: string):
 
 /**
  * 创建视频分享数据
- * @param videoUrl 视频路径(支持本地路径和网络 URL)
+ * @param url 视频路径(支持本地路径和网络 URL)
  * @param title 分享标题
  * @param summary 分享描述
  * @returns 分享数据对象
  */
-function createVideoShareData(videoUrl: string, title: string, summary: string): systemShare.SharedData | null {
-	if (videoUrl === '') {
+function createVideoShareData(url: string, title: string, summary: string): systemShare.SharedData | null {
+	if (url === '') {
 		return null;
 	}
 
-	const filePath = UTSHarmony.getResourcePath(videoUrl);
+	const filePath = UTSHarmony.getResourcePath(url);
 	const utdTypeId = getUtdTypeByPath(filePath, utd.UniformDataType.VIDEO);
 
 	return new systemShare.SharedData({
@@ -79,17 +79,17 @@ function createVideoShareData(videoUrl: string, title: string, summary: string):
 
 /**
  * 创建音频分享数据
- * @param audioUrl 音频路径(支持本地路径和网络 URL)
+ * @param url 音频路径(支持本地路径和网络 URL)
  * @param title 分享标题
  * @param summary 分享描述
  * @returns 分享数据对象
  */
-function createAudioShareData(audioUrl: string, title: string, summary: string): systemShare.SharedData | null {
-	if (audioUrl === '') {
+function createAudioShareData(url: string, title: string, summary: string): systemShare.SharedData | null {
+	if (url === '') {
 		return null;
 	}
 
-	const filePath = UTSHarmony.getResourcePath(audioUrl);
+	const filePath = UTSHarmony.getResourcePath(url);
 	const utdTypeId = getUtdTypeByPath(filePath, utd.UniformDataType.AUDIO);
 
 	return new systemShare.SharedData({
@@ -160,16 +160,16 @@ function createFileShareData(filePath: string, title: string, summary: string):
 
 /**
  * 创建链接分享数据
- * @param href 链接地址
+ * @param url 链接地址
  * @param title 分享标题
  * @param summary 分享描述
  * @returns 分享数据对象
  */
-function createLinkShareData(href: string, title: string, summary: string): systemShare.SharedData {
+function createLinkShareData(url: string, title: string, summary: string): systemShare.SharedData {
 	return new systemShare.SharedData({
 		utd: utd.UniformDataType.HYPERLINK,
 		title: title,
-		content: href,
+		content: url,
 		description: summary
 	});
 }
@@ -194,12 +194,11 @@ function createTextShareData(title: string, summary: string): systemShare.Shared
  * @param options.type 分享类型: text(文本) | image(图片) | video(视频) | audio(音频) | file(文件) | link(链接)
  * @param options.title 分享标题
  * @param options.summary 分享描述/内容
- * @param options.href 链接地址或文件路径
- * @param options.imageUrl 图片/视频/音频路径(支持本地路径和网络 URL)
+ * @param options.url 资源路径(图片/视频/音频/文件路径或链接地址,支持本地路径和网络 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 {
+export function share(type: string, title: string, summary: string, url: string, success: () => void, fail: (error: string) => void): void {
 	// 获取UI上下文
 	const uiContext: UIContext = UTSHarmony.getCurrentWindow()?.getUIContext();
 	const context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;
@@ -210,32 +209,33 @@ export function share(type: string, title: string, summary: string, href: string
 
 	switch (type) {
 		case ShareType.IMAGE:
-			shareData = createImageShareData(imageUrl, title, summary);
+			shareData = createImageShareData(url, title, summary);
 			errorMsg = '图片路径不能为空';
 			break;
 
 		case ShareType.VIDEO:
-			shareData = createVideoShareData(imageUrl, title, summary);
+			shareData = createVideoShareData(url, title, summary);
 			errorMsg = '视频路径不能为空';
 			break;
 
 		case ShareType.AUDIO:
-			shareData = createAudioShareData(imageUrl, title, summary);
+			shareData = createAudioShareData(url, title, summary);
 			errorMsg = '音频路径不能为空';
 			break;
 
 		case ShareType.FILE:
-			shareData = createFileShareData(href, title, summary);
+			shareData = createFileShareData(url, title, summary);
 			errorMsg = '文件路径不能为空';
 			break;
 
 		case ShareType.LINK:
-			shareData = createLinkShareData(href, title, summary);
+			shareData = createLinkShareData(url, title, summary);
 			break;
 
 		default:
 			// 默认为文本分享
 			shareData = createTextShareData(title, summary);
+			errorMsg = '分享内容不能为空';
 			break;
 	}
 

+ 14 - 0
uni_modules/cool-share/utssdk/app-ios/PrivacyInfo.xcprivacy

@@ -0,0 +1,14 @@
+<?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>
+	<key>NSPrivacyAccessedAPITypes</key>
+	<array/>
+	<key>NSPrivacyCollectedDataTypes</key>
+	<array/>
+	<key>NSPrivacyTracking</key>
+	<false/>
+	<key>NSPrivacyTrackingDomains</key>
+	<array/>
+</dict>
+</plist>

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

@@ -0,0 +1,3 @@
+{
+	"deploymentTarget": "12"
+}

+ 287 - 0
uni_modules/cool-share/utssdk/app-ios/index.uts

@@ -0,0 +1,287 @@
+import { UIActivityViewController, UIImage } from "UIKit";
+import { URL, Data } from "Foundation";
+import { ShareWithSystemOptions } from "../interface.uts";
+
+/**
+ * 分享类型枚举
+ */
+const ShareType = {
+	TEXT: "text", // 纯文本分享
+	IMAGE: "image", // 图片分享
+	VIDEO: "video", // 视频分享
+	AUDIO: "audio", // 音频分享
+	FILE: "file", // 文件分享
+	LINK: "link" // 链接分享
+};
+
+/**
+ * 判断是否为网络 URL
+ * @param url 地址
+ * @returns 是否为网络 URL
+ */
+function isNetworkUrl(url: string): boolean {
+	return url.startsWith("http://") || url.startsWith("https://");
+}
+
+/**
+ * 下载网络文件到本地缓存
+ * @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 ?? "未知错误"}`);
+		}
+	});
+}
+
+/**
+ * 处理文件路径并加载数据
+ * @param filePath 文件路径
+ * @returns Data 对象或 null
+ */
+function loadFileData(filePath: string): Data | null {
+	const absolutePath = UTSiOS.convert2AbsFullPath(filePath);
+	const fileURL = new URL((fileURLWithPath = absolutePath));
+	const data = UTSiOS.try(new Data((contentsOf = fileURL)), "?");
+	return data;
+}
+
+/**
+ * 创建文本分享内容
+ * @param title 标题
+ * @param summary 描述
+ * @param url 链接
+ * @returns 分享内容数组
+ */
+function createTextShareItems(title: string, summary: string, url: string): any[] {
+	// 组合分享内容
+	let content = "";
+	if (title != "") {
+		content = title;
+	}
+	if (summary != "") {
+		content = content == "" ? summary : content + "\n" + summary;
+	}
+	if (url != "") {
+		content = content == "" ? url : content + "\n" + url;
+	}
+
+	// 如果内容为空,使用默认文本
+	if (content == "") {
+		content = "分享内容";
+	}
+
+	return [content];
+}
+
+/**
+ * 创建图片分享内容
+ * @param url 图片路径
+ * @param success 成功回调
+ * @param fail 失败回调
+ */
+function createImageShareItems(
+	url: string,
+	success: (items: any[]) => void,
+	fail: (error: string) => void
+): void {
+	if (url == "") {
+		fail("图片路径不能为空");
+		return;
+	}
+
+	const handleImagePath = (localPath: string) => {
+		const absolutePath = UTSiOS.convert2AbsFullPath(localPath);
+		const image = new UIImage((contentsOfFile = absolutePath));
+
+		if (image == null) {
+			fail("图片加载失败");
+			return;
+		}
+
+		success([image]);
+	};
+
+	if (isNetworkUrl(url)) {
+		// 网络图片先下载
+		downloadNetworkFile(url, handleImagePath, fail);
+	} else {
+		// 本地图片直接处理
+		handleImagePath(url);
+	}
+}
+
+/**
+ * 创建文件分享内容(视频、音频、文件)
+ * @param filePath 文件路径
+ * @param success 成功回调
+ * @param fail 失败回调
+ */
+function createFileShareItems(
+	filePath: string,
+	success: (items: any[]) => void,
+	fail: (error: string) => void
+): void {
+	if (filePath == "") {
+		fail("文件路径不能为空");
+		return;
+	}
+
+	const handleFilePath = (localPath: string) => {
+		const data = loadFileData(localPath);
+
+		if (data == null) {
+			fail("文件加载失败");
+			return;
+		}
+
+		const absolutePath = UTSiOS.convert2AbsFullPath(localPath);
+		const fileURL = new URL.init((fileURLWithPath = absolutePath));
+
+		success([data, fileURL]);
+	};
+
+	if (isNetworkUrl(filePath)) {
+		// 网络文件先下载
+		downloadNetworkFile(filePath, handleFilePath, fail);
+	} else {
+		// 本地文件直接处理
+		handleFilePath(filePath);
+	}
+}
+
+/**
+ * 启动系统分享界面
+ * @param items 分享内容数组
+ * @param success 成功回调
+ * @param fail 失败回调
+ */
+function presentShareController(
+	items: any[],
+	success: () => void,
+	fail: (error: string) => void
+): void {
+	DispatchQueue.main.async(
+		(execute = (): void => {
+			const activityViewController = new UIActivityViewController(
+				(activityItems = items),
+				(applicationActivities = nil)
+			);
+
+			const currentVC = UTSiOS.getCurrentViewController();
+			if (currentVC == null) {
+				fail("无法获取当前视图控制器");
+				return;
+			}
+
+			currentVC.present(
+				activityViewController,
+				(animated = true),
+				(completion = () => {
+					success();
+				})
+			);
+		})
+	);
+}
+
+/**
+ * 系统分享功能
+ * @param options 分享参数
+ * @param options.type 分享类型: text(文本) | image(图片) | video(视频) | audio(音频) | file(文件) | link(链接)
+ * @param options.title 分享标题
+ * @param options.summary 分享描述/内容
+ * @param options.url 资源路径(图片/视频/音频/文件路径或链接地址,支持本地路径和网络 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 url = options.url ?? "";
+
+	// 根据分享类型创建对应的内容
+	if (type == (ShareType["TEXT"] as string) || type == (ShareType["LINK"] as string)) {
+		// 文本或链接分享
+		const items = createTextShareItems(title, summary, url);
+		presentShareController(
+			items,
+			() => {
+				options.success?.();
+			},
+			(error: string) => {
+				options.fail?.(error);
+			}
+		);
+	} else if (type == (ShareType["IMAGE"] as string)) {
+		// 图片分享
+		createImageShareItems(
+			url,
+			(items: any[]) => {
+				presentShareController(
+					items,
+					() => {
+						options.success?.();
+					},
+					(error: string) => {
+						options.fail?.(error);
+					}
+				);
+			},
+			(error: string) => {
+				options.fail?.(error);
+			}
+		);
+	} else if (
+		type == (ShareType["VIDEO"] as string) ||
+		type == (ShareType["AUDIO"] as string) ||
+		type == (ShareType["FILE"] as string)
+	) {
+		// 视频、音频、文件分享
+		createFileShareItems(
+			url,
+			(items: any[]) => {
+				presentShareController(
+					items,
+					() => {
+						options.success?.();
+					},
+					(error: string) => {
+						options.fail?.(error);
+					}
+				);
+			},
+			(error: string) => {
+				options.fail?.(error);
+			}
+		);
+	} else {
+		// 未知类型,默认使用文本分享
+		const items = createTextShareItems(title, summary, url);
+		presentShareController(
+			items,
+			() => {
+				options.success?.();
+			},
+			(error: string) => {
+				options.fail?.(error);
+			}
+		);
+	}
+}

+ 22 - 2
uni_modules/cool-share/utssdk/interface.uts

@@ -1,9 +1,29 @@
 export type ShareWithSystemOptions = {
+	/**
+	 * 分享类型: 
+	 * text(文本) | image(图片) | video(视频) | audio(音频) | file(文件) | link(链接)
+	 */
 	type: string;
+	/**
+	 * 分享标题
+	 */
 	title?: string;
+	/**
+	 * 分享描述或内容
+	 */
 	summary?: string;
-	href?: string;
-	imageUrl?: string;
+	/**
+	 * 分享资源路径:
+	 * 如果是图片/视频/音频/文件,填写资源路径或网络URL
+	 * 如果是link,填写链接地址
+	 */
+	url?: string;
+	/**
+	 * 分享成功回调
+	 */
 	success?: () => void;
+	/**
+	 * 分享失败回调,返回错误信息
+	 */
 	fail?: (error: string) => void;
 };