Files
WAI_Project_UNIX/uni_modules/cool-share/utssdk/app-android/index.uts
2025-10-30 19:28:09 +08:00

462 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}