Android Q 响应intent.action.VIEW,并复制对应的文件
需求:将微信和QQ等第三方应用里的文件直接分享到自己的应用,在自己应用的外部存储目录下复制一份对应文件。
编译版本:29
添加intent-filter
首先在响应的Activity添加意图过滤器,在android:mimeType中添加需要响应的文件类型
<activity android:name=".view.common.ShareFilesActivity">
<intent-filter android:label="分享"
tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
<data android:mimeType="image/jpeg" />
<data android:mimeType="image/png" />
<data android:mimeType="image/bmp" />
<data android:mimeType="image/tiff" />
<data android:mimeType="image/gif" />
<data android:mimeType="image/jpeg" />
<data android:mimeType="image/x-ms-bmp" />
<data android:mimeType="image/png" />
<data android:mimeType="image/x-pcx" />
<data android:mimeType="image/targa" />
<data android:mimeType="image/x-photoshop" />
<data android:mimeType="video/mpeg" />
<data android:mimeType="audio/mp4"/>
<data android:mimeType="audio/mp3"/>
<data android:mimeType="audio/mp3"/>
<data android:mimeType="video/x-ms-wmv"/>
<data android:mimeType="video/x-ms-wm"/>
<data android:mimeType="video/x-ms-wmx"/>
<data android:mimeType="application/octet-stream" />
<data android:mimeType="application/pdf" />
<data android:mimeType="application/msword" />
<data android:mimeType="application/pdf" />
<data android:mimeType="application/zip" />
<data android:mimeType="application/x-xls" />
<data android:mimeType="application/msword" />
<data android:mimeType="application/x-ppt"/>
<data android:mimeType="application/vnd.ms-powerpoint"/>
</intent-filter>
</activity>
处理Intent
@Override
public void initExtras(@Nullable Intent intent) {
if (intent == null)return;
String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)){
if (SCHEME_FILE.equals(intent.getScheme()) || SCHEME_CONTENT.equals(intent.getScheme())) {
Uri uri = intent.getData();
copyFileActionView(uri);
}
}
}
解析Uri
android10以后,只需要考虑沙盒里的文件uri和共享文件(匿名uri)、通过文件选择器获取到的uri的转换;其他类型,要么转换不成File,要么拿不到,也就不用再考虑了事实上android10之后,是无法拿到外部文件的绝对路径的,唯一能做的,只是把共享文件复制到沙盒目录下,然后再进行文件操作。沙盒里的文件(file开头),可以直接转成File使用,共享文件(content开头)如果要操作,需要先复制到沙盒目录下。
private static File uriToFileCopy(Uri uri, Context context) throws IOException{
File file = null;
if(uri == null) return file;
//android10以上转换
if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
file = new File(uri.getPath());
InputStream is = new FileInputStream(file);
File path = FilePathProvider.getPublicDir(context, "enclosure" +
"/" + DateTimeUtils.formatDatetime(new Date(),FORMAT_DATE3));
if (!path.exists()){
path.mkdir();
}
File cache = new File(path.getAbsolutePath(), file.getName());
FileOutputStream fos = new FileOutputStream(cache);
copyFileStream(is,fos);
file = cache;
} else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
//把文件复制到沙盒目录
ContentResolver contentResolver = context.getContentResolver();
String displayName = null;
//注释掉的方法可以获取到原文件的文件名,但是比较耗时
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor.moveToFirst()) {
displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
InputStream is = contentResolver.openInputStream(uri);
File path = FilePathProvider.getPublicDir(context, "enclosure" +
"/" + DateTimeUtils.formatDatetime(new Date(),FORMAT_DATE3));
if (!path.exists()){
path.mkdir();
}
File cache = new File(path.getAbsolutePath(), displayName);
FileOutputStream fos = new FileOutputStream(cache);
copyFileStream(is,fos);
file = cache;
}
return file;
}
放到异步线程
private void copyFileActionView(Uri path){
Flowable.just(path)
.subscribeOn(Schedulers.io())
.map((Function<Uri, ResponseModel<String>>) s -> {
try {
File file = uriToFileCopy(s,mView.getContext());
if (file == null){
return TaskDetailsBiz.obtainResponse(0,mView.getContext().getString(R.string.share_file_fail,"返回为NULL"),null);
}else{
return TaskDetailsBiz.obtainResponse(1,mView.getContext().getString(R.string.share_file_success),null);
}
}catch (Exception e){
e.printStackTrace();
return TaskDetailsBiz.obtainResponse(0,mView.getContext().getString(R.string.share_file_fail,e.getMessage()),null);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new ResourceSubscriber<ResponseModel<String>>() {
@Override
public void onNext(ResponseModel<String> responseModel) {
if (responseModel.getStatus()==0){
//失败
}else {
//成功
}
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
}
});
}
public class ResponseModel<T> implements Serializable {
/**返回状态--失败 */
public static final int STATUS_FAILED = 0;
/**返回状态--成功 */
public static final int STATUS_SUCCESS = 1;
/**返回状态 0-失败 1-成功 */
private int resultStatus;
/**返回消息 */
private String resultMessage;
/**返回数据 */
private T result;
//set and get
}
/**
* 根据参数构建一个Response
* @param code 状态码
* @param message 消息
* @param t 内容实体
* @param <T> 内容类型
* @return response
*/
public static <T> ResponseModel<T> obtainResponse(int code , String message,T t){
ResponseModel<T> response = new ResponseModel<>();
response.setMessage(message);
response.setStatus(code);
response.setResult(t);
return response;
}
/**
* 复制文件流
* @param inputStream 输入流
* @param outputStream 输出流
* @throws IOException IO异常
*/
private static void copyFileStream(InputStream inputStream , OutputStream outputStream) throws IOException{
int byteread = 0;
byte[] buffer = new byte[1024];
while ( (byteread = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, byteread);
}
inputStream.close();
outputStream.close();
}
以上,就可以在QQ或微信中选择其他应用打开相应文件,并复制到自己的目录进行操作。