WPS二次开发系列:如何使用WPS返回的FileUri
作者持续关注 WPS二次开发专题系列,持续为大家带来更多有价值的WPS开发技术细节,如果能够帮助到您,请帮忙来个一键三连,更多问题请联系我(QQ:250325397)
目录
什么是FileUri
在SDK中的使用场景
打开文档时候
文档保存/事件时候
第三方应用中使用FileUri
什么是FileUri
若要安全地将应用中的文件提供给其他应用,您需要配置应用,以内容 URI 的形式提供文件的安全句柄。Android FileProvider 组件会根据您在 XML 中指定的内容生成文件的内容 URI。
详细请参考 WPS二次开发系列:如何对打开文档路径FileUri授权
在SDK中的使用场景
打开文档时候
在SDK调用打开文档前,需要主要将文件本地路径filePath转换成fileUri,详见WPS二次开发系列:如何对打开文档路径FileUri授权
文档保存/事件时候
文档保存/关闭事件在SDK的回调接口中均返回了WPS编辑保存后的文档路径(fileUri), 这个FileUri是WPS临时授权给第三方应用使用的FileUri,那么该如何在其它第三方应用中使用呢?
文档保存/关闭事件:
FileApi fileApi = WpsSdk.getInstance().getApi(FileApi.class);
if (fileApi != null) {fileApi.addEventListener(SingleOpenActivity.this, ApiEvent.DocumentAfterSave, new EventListener() {@Overridepublic void onEvent(String eventName, Bundle bundle) {//注意在高版本Android系统中,第三方应用是无法读取WPS私有路径,需要通过获取WPS提供的URI来访问文档数据Uri currentFileUri = bundle.getParcelable("CurrentFileUri");Log.d("WpsSdk", "demo onEvent DocumentAfterSave : s=" + s + " bundle=" + bundle + " path=" + path+ " currentFileUri="+currentFileUri);}});fileApi.addEventListener(SingleOpenActivity.this, ApiEvent.DocumentAfterClose, new EventListener() {@Overridepublic void onEvent(String s, Bundle bundle) {Uri currentFileUri = bundle.getParcelable("CurrentFileUri");Log.d("WpsSdk", "demo onEvent DocumentAfterClose : s=" + s + " bundle=" + bundle + " path=" + path + " currentFileUri=" + currentFileUri);Utils.showToast(SingleOpenActivity.this, "文档路径:" + currentFileUri);}});//注意在调用文档打开之前进行注册fileApi.openFile(this, fileUri, bundle);
}
注意上面示例代码中返回的:currentFileUri 就是WPS授权给第三方使用的文件路径
第三方应用中使用FileUri
那么如何在第三方应用中使用curentFileUri呢,这里关键是需要通过
InputStream inputStream = context.getContentResolver().openInputStream(uri);
来进行读写。
详见Demo使用参考,根据SDK返回的currentFileUri路径,将文件从WPS沙盒空间拷贝文件到第三方应用自己的私有空间,如Android/data/<包名>/files/output/ 目录下
String outFile = FileUtil.copyFileFromUri(MainActivity.this, fileUri, "output");
完整拷贝工具类参考示例代码:
package cn.wps.sdk.demo.util;import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.TextUtils;import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;public class FileUtil {private static final int IO_BUFFER_SIZE = 8192;public static String getFileName(String filePath){if (null == filePath)return null;return new File(filePath).getName();}/**** @param uri 文件uri* @param fileDir 沙盒目录 files/fileDir* @return 沙盒路径*/public static String copyFileFromUri(Context context, Uri uri, String fileDir) {File dirFile = getFileDir(context, fileDir);String fileName = parseFileName(context, uri);String destPath = dirFile.getAbsolutePath() + File.separator + fileName;if (new File(destPath).exists()) {new File(destPath).deleteOnExit();}InputStream inputStream = null;try {inputStream = context.getContentResolver().openInputStream(uri);} catch (FileNotFoundException e) {throw new RuntimeException(e);}if (copyFile(inputStream, destPath)) {return destPath;}return null;}public static boolean copyFile(InputStream in, String destPath){return copyFile(in, destPath, true);}public static boolean copyFile(InputStream in, String destPath, boolean closeInput){if (in == null || destPath == null)return false;File outFile = new File(destPath);if (!prepareFilePath(outFile))return false;FileOutputStream os = null;try{os = new FileOutputStream(outFile);copy(in, os);return true;}catch (Exception e){e.printStackTrace();}finally{closeQuietly(os);if (closeInput) closeQuietly(in);}return false;}public static void copy(InputStream in, OutputStream out) throws IOException{copy(in, out, null);}public static void copy(InputStream in, OutputStream out, byte[] buffer) throws IOException{if (null == buffer)buffer = new byte[IO_BUFFER_SIZE];int read;while ((read = in.read(buffer)) != -1){out.write(buffer, 0, read);}}private static boolean prepareFilePath(File file){File parent = file.getParentFile();assert parent != null;if (parent.exists()) {return true;}return parent.mkdirs();}public static void closeQuietly(FileOutputStream out){if (null == out)return;try {out.flush();try {out.getFD().sync(); // bug 314867} catch (Exception ignore) {}out.close();} catch (IOException ignore){}}public static void closeQuietly(Closeable closable){if (null == closable)return;try {if (closable instanceof FileOutputStream){FileOutputStream _out = (FileOutputStream)closable;_out.flush();try {_out.getFD().sync();} catch (Exception ignore) {}}else if (closable instanceof RandomAccessFile){RandomAccessFile _out = (RandomAccessFile)closable;try {_out.getFD().sync();} catch (Exception ignore) {}}closable.close();} catch (IOException ignore){}}private static String parseFileName(Context context, Uri uri) {if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {return StringUtil.getNamePart(uri.getPath());}String name = queryDisplayName(context, uri);if (!TextUtils.isEmpty(name)) {return name;}name = queryOtherColumn(context, uri);if (!TextUtils.isEmpty(name)) {return name;}if (TextUtils.isEmpty(name)) {String urlPath = uri.getPath();String namePart = StringUtil.getNamePart(urlPath);String extPart = StringUtil.pathExtension(urlPath);if (!TextUtils.isEmpty(namePart) && !TextUtils.isEmpty(extPart)) {name = namePart;}}return name;}private static String queryDisplayName(Context context, Uri uri) {ContentResolver resolver = context.getContentResolver();Cursor cur = null;String name = null;try {cur = resolver.query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);if (cur != null && cur.getCount() == 1 && cur.moveToFirst()) {final int displayNameIndex = cur.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);if (displayNameIndex != -1) {String displayName = cur.getString(displayNameIndex);if (!TextUtils.isEmpty(displayName)) {String namePart =StringUtil.getNamePart(displayName);String ext = StringUtil.pathExtension(displayName);if (!TextUtils.isEmpty(namePart) && !TextUtils.isEmpty(ext)) {name = displayName.trim();}}}}} catch (Exception ignore) {} finally {if (cur != null) {cur.close();}}return name;}private static String queryOtherColumn(Context context, Uri uri) {ContentResolver resolver = context.getContentResolver();Cursor cur = null;String name = null;try {cur = resolver.query(uri, null, null, null, null);if (cur != null && cur.getCount() == 1 && cur.moveToFirst()) {if (TextUtils.isEmpty(name)) {int fileNameIndex = cur.getColumnIndex("file_name");if (fileNameIndex != -1) {String fileName = cur.getString(fileNameIndex);if (!TextUtils.isEmpty(fileName)) {name = fileName;}}}if (TextUtils.isEmpty(name)) {int dataIndex = cur.getColumnIndex(MediaStore.MediaColumns.DATA);if (dataIndex != -1) {String dataPath = cur.getString(dataIndex);if (!TextUtils.isEmpty(dataPath)) {name = new File(dataPath).getName();}}}}} catch (Exception ignore) {} finally {if (cur != null) {cur.close();}}return name;}public static File getFileDir(Context context, String fileDir) {File file = context.getExternalFilesDir(fileDir);if (!file.exists()) {boolean result = file.mkdirs();if (!result) {throw new RuntimeException("create file dir fail");}}return file;}
}
相关文章:
WPS二次开发系列:如何使用WPS返回的FileUri
作者持续关注 WPS二次开发专题系列,持续为大家带来更多有价值的WPS开发技术细节,如果能够帮助到您,请帮忙来个一键三连,更多问题请联系我(QQ:250325397) 目录 什么是FileUri 在SDK中的使用场景 打开文档时…...
python删除一个文件夹所有文件
在Python中,可以使用os模块来删除一个文件夹中的所有文件,但保留文件夹本身。以下是一个简单的例子: import osdef delete_files_in_folder(folder_path):for filename in os.listdir(folder_path):file_path os.path.join(folder_path, fi…...

overflow:hidden对解决外边距塌陷的个人理解
外边距塌陷: 子元素的上外边距大于父元素的上外边距,导致边距折叠,取两者之间最大值,即子元素外边距,导致父元素上外边距失效。 解决办法:在父元素样式添加overflow:hidden;或者border:1px solid black;(不…...
【linux软件基础知识】- 文件的概念:Linux 中的文件
Linux 中的文件 在 Linux 中,文件是存储在存储设备(例如硬盘驱动器或固态驱动器)上的数据项的集合。 文件被组织为字节序列,并由文件系统中的唯一名称来标识。 以下是 Linux 中文件的一些关键特征: 字节序列:Linux 中的文件被视为字节序列。 每个字节可以表示一个字符…...
Context capture/Pix4Dmapper/AutoCAD/CASS/EPS软件的安装流程与使用方法;土方量计算;无人机摄影测量数据处理
目录 专题一 无人机摄影测量技术应用现状及其发展 专题二 基本原理和关键技术讲解 专题三 无人机影像外业数据获取 专题四 数据处理环境建立与软件熟悉 专题五 GNSS数据土方量计算 专题六 基于无人机影像数据的正射影像制作 专题七 基于无人机影像数据的三维模型制作 专…...
算法系列之堆排序实践哪家强
1.概念 堆排序是一种树形选择排序,是对简单选择排序的有效改进和优化。 堆(heap),这里所说的堆是数据结构中的堆(对应于算法),而不是内存模型中的堆(数据存储形式,还比如:栈&#…...

01-win10安装Qt5
Qt5安装教程 下载Qt5官网下载(下载很慢)镜像网站下载(有些版本没有资源)迅雷下载(推荐)百度网盘下载(推荐)安装Qt5下载Qt5 官网下载(下载很慢) 【注意】:官网下载非常慢,没有镜像下载时常20+ Qt 官网有一个专门的资源下载网站,所有的开发环境和相关工具都可以从这…...
mybatis使用及配置相关,仅做个人记录
在spring-boot项目中mybatis的配置文件在yml文件中,并没有mybatisconfig.xml文件 yml文件中配置:(来源:https://blog.51cto.com/u_16213723/8747999) mybatis:# XML文件路径,可配置多个,逗号分…...

【STM32 |新建一个工程】基于标准库(库函数)新建工程
目录 STM32开发方式 库函数文件夹 建工程步骤 库函数工程建立 建立工程总结 STM32开发方式 目前stm32的开发方式主要有基于寄存器的方式、基于标准库的方式(库函数的方式)、基于HAL库的方式基于库函数的方式是使用ST官方提供的封装好的函数&…...
C#利用ClearScript执行Javascript脚本
1,新建.netframework winform工程 2,打开nuget程序包管理界面,安装Microsoft.ClearScript.V8,Microsoft.ClearScript.V8.Native.win-x64. 3,编写Javascript脚本,另存为demo.js function testFunc(t) {return t "…...

住宅ip与数据中心ip代理的区别是什么
代理通常意味着“替代”。它是用户设备和目标服务器之间的中介,允许在不同的IP地址下上网。代理ip根据来源分类可分住宅ip与数据中心ip,二者之间区别是什么呢? 住宅ip是由互联网服务提供商(ISP)提供给家庭的IP地址。出于这个原因,…...

【计算机网络】数据链路层的功能
数据链路层的基本功能: 封装成帧透明传输差错检测 数据链路层使用的信道主要有两种 点对点信道——PPP协议广播信道——CSMA/CD协议(有线局域网)、CSMA/CA协议(无线局域网) 数据链路层所处的地位 从图中可以看出,数据从主机H1送到主机H2需要在路径中…...

信号线电路串联电阻
简介 两芯片端串联一个电阻,在靠近发送端或接收端。 一般串联的是0Ω, 22Ω, 33Ω的电阻,也可能更大。 目的 1.解决信号反射问题,吸收反射。 问题如下: pcb单端阻抗过大,而接收端是cmos输入,使得接收端…...
手机App防沉迷系统-算法
import java.util.*; public class Main{public static void main(String[] args){Scanner innew Scanner(System.in);int nInteger.parseInt(in.nextLine());//已注册app列表List<Log> listnew ArrayList<>();for(int k0;k<n;k){String[] strin.nextLine().spl…...

day3_prefixSum
一、前缀和技巧 重点 前缀和技巧适用于快速、频繁地计算一个索引区间内的元素之和 个人理解;预计算,空间换时间 1.(一维数组的前缀和)303区域和检索-数组不可变 获取闭区间值 [left,right] -> preSum[right 1] - preSum[left],其中preSum[right…...

Redis过期删除策略和内存淘汰策略有什么区别?
Redis过期删除策略和内存淘汰策略有什么区别? 前言过期删除策略如何设置过期时间?如何判定 key 已过期了?过期删除策略有哪些?Redis 过期删除策略是什么? 内存淘汰策略如何设置 Redis 最大运行内存?Redis 内…...

【计算机网络】物理层传输介质 习题3
双绞线是用两根绝缘导线绞合而成的,绞合的目的是( )。 A.减少干扰 B.提高传输速度 C.增大传输距离 D.增大抗拉强度 在电缆中采用屏蔽技术带来的好处主要是( ) A.减少信号衰减 B. 减少电磁干扰辐射 C.减少物理损坏 D. 减少电缆的阻抗 利用一根同轴电缆互连主机构成…...

智能座舱语音助手产品方案
一、用户调研与痛点分析 1.目标用户分析 用户画像 性别女性年龄50地域2-3线城市职业退休或退居二线教育中专、 大专、 本科财务家庭财务管理者爱好享受生活、 照顾家庭标签有闲有小钱二、产品定位与卖点提炼 购车目的 愉悦自我, 专属于自己的座驾: 家…...

经典面试题之滑动窗口专题
class Solution { public:int minSubArrayLen(int target, vector<int>& nums) {// 长度最小的子数组 // 大于等于 targetint min_len INT32_MAX;// 总和int sum 0;int start 0; // 起点for(int i 0; i< nums.size(); i) {sum nums[i];while(sum > targe…...

网络编程入门之UDP编程
欢迎各位帅哥美女来捧场,本文是介绍UDP网络编程。在这里,你会见到最详细的教程;细致到每一行代码,每一个api的由来和使用它的目的等。 目录 1.UDP相关API 1.1.两个类 1.2.两个类中的方法 2.UDP编程 2.1.大体框架 2.2.内容构…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...

在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...