作者持续关注WPS二次开发专题系列,持续为大家带来更多有价值的WPS开发技术细节,如果能够帮助到您,请帮忙来个一键三连,更多问题请联系我(QQ:250325397)
什么是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() {
@Override
public 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() {
@Override
public 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;
}
}