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 url 图片路径(支持本地路径和网络 URL) * @param title 分享标题 * @param success 成功回调 * @param fail 失败回调 */ function createImageShareIntent( url: string, title: string, success: (intent: Intent) => void, fail: (error: string) => void ): void { if (url == "") { fail("图片路径不能为空"); return; } createFileUriAsync( url, (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 url 视频路径(支持本地路径和网络 URL) * @param title 分享标题 * @param success 成功回调 * @param fail 失败回调 */ function createVideoShareIntent( url: string, title: string, success: (intent: Intent) => void, fail: (error: string) => void ): void { if (url == "") { fail("视频路径不能为空"); return; } createFileUriAsync( url, (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 url 音频路径(支持本地路径和网络 URL) * @param title 分享标题 * @param success 成功回调 * @param fail 失败回调 */ function createAudioShareIntent( url: string, title: string, success: (intent: Intent) => void, fail: (error: string) => void ): void { if (url == "") { fail("音频路径不能为空"); return; } createFileUriAsync( url, (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 url 链接地址 * @param title 分享标题 * @param summary 分享描述 * @param success 成功回调 * @param fail 失败回调 */ function createLinkShareIntent( url: string, title: string, summary: string, success: (intent: Intent) => void, fail: (error: string) => void ): void { if (url == "") { fail("链接地址不能为空"); return; } // 组合分享内容:标题 + 描述 + 链接 let content = ""; if (title != "") { content = title; } if (summary != "") { content = content == "" ? summary : content + "\n" + summary; } if (url != "") { content = content == "" ? url : content + "\n" + url; } 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 url 附加链接(可选) * @param success 成功回调 */ function createTextShareIntent( title: string, summary: string, url: string, success: (intent: Intent) => void ): void { // 组合分享内容 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 = "分享内容"; } 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.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 ?? ""; // 成功和失败回调 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(url, title, onSuccess, onFail); } else if (type == ShareType["VIDEO"]) { createVideoShareIntent(url, title, onSuccess, onFail); } else if (type == ShareType["AUDIO"]) { createAudioShareIntent(url, title, onSuccess, onFail); } else if (type == ShareType["FILE"]) { createFileShareIntent(url, title, onSuccess, onFail); } else if (type == ShareType["LINK"]) { createLinkShareIntent(url, title, summary, onSuccess, onFail); } else { // 默认为文本分享 createTextShareIntent(title, summary, url, onSuccess); } }