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