EROS是基于 weex 封装、面向前端的 vue 写法的一整套 APP 开源解决方案。
1.为什么不按照EROS官方文档新建插件项目?
之前按照官方文档创建插件项目,项目中添加该插件项目依赖后出现了依赖文件重复,SDK依赖版本不同导致build fail的情况,因此迫不得已才在框架源码上进行修改。
包括文件选择和文件上传两个部分,文件选择使用的github上的MultiType-FilePicker项目 在此对@fishwjy提出感谢,支持根据后缀名进行筛选文件,支持选择多个文件。
文件上传使用的是框架中图片上传使用的AxiosManager类(基于okhttp3进行封装),支持自定义header,cookie部分使用的是系统自带android.webkit.CookieSyncManager,自动添加cookie到header中。
支持自定义header,自动添加cookie,调用的是系统自带的DownloadManager。不足之处是需要传入文件名(不含后缀名)和后缀名,无法根据响应header中Content-Disposition判断文件名。
weex.requireModule("FileModule").downloadFile(
{
url:"xxxxxxx",//下载地址
name:"yyyyyyy"//文件名(不含后缀名)
suffix: "zzzzzzz",//后缀名(例如 "docx")
params:{aaa:"bbb"},//自定义请求参数[可选]
headers: {//自定义header[可选]
Referer:'aaaaaa'
}
},
function(resData) {
weex.requireModule("bmModal").toast({
message:
resData.message == "success"
? "正在下载,请稍后在通知中心查看"
: "下载失败"
});
}
);
weex.requireModule("FileModule").uploadFile(
{
url:"xxxxxxxx",//上传地址
maxCount:10,//最大可选择的文件数量
suffix:"rar,zip,7z",//支持的文件类型
params:{aaa:"bbb"},//自定义请求参数[可选](其中有一个可选参数,key为ContentDispositionName,不填的默认值为"file",用于指定POST请求中的RequestBody中的该文件对应部分的Content-Disposition中的name属性的值,参数的值应与后端协商确定,后端根据该值进行解析,参见下方图片)
headers: {
Referer:"yyyyyyy"//自定义请求头[可选]
}
},
function(resData) {
weex.requireModule("bmModal").toast({
message:
resData
});
}
);
compileSdkVersion 26 targetSdkVersion 26
添加依赖
dependencies{
compile 'com.vincent.filepicker:MultiTypeFilePicker:1.0.8'
}
创建
public class FileModule extends WXModule {
@JSMethod
public void uploadFile(String params, JSCallback jsCallback) {
WeexEventBean eventBean = new WeexEventBean();
eventBean.setContext(mWXSDKInstance.getContext());
eventBean.setKey(WXEventCenter.EVENT_FILE_UPLOAD);
eventBean.setJsParams(params);
eventBean.setJscallback(jsCallback);
ManagerFactory.getManagerService(DispatchEventManager.class).getBus().post(eventBean);
}
@JSMethod
public void downloadFile(String params, JSCallback jsCallback) {
WeexEventBean eventBean = new WeexEventBean();
eventBean.setContext(mWXSDKInstance.getContext());
eventBean.setKey(WXEventCenter.EVENT_FILE_DOWNLOAD);
eventBean.setJsParams(params);
eventBean.setJscallback(jsCallback);
ManagerFactory.getManagerService(DispatchEventManager.class).getBus().post(eventBean);
}
}
添加3个事件字符串常量定义
public static final String EVENT_FILE_PICK = "EVENT_FILE_PICK";
public static final String EVENT_FILE_UPLOAD = "EVENT_FILE_UPLOAD";
public static final String EVENT_FILE_DOWNLOAD = "EVENT_FILE_DOWNLOAD";
创建
package com.eros.framework.event.file;
import android.Manifest;
import android.app.DownloadManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.widget.Toast;
import com.eros.framework.constant.Constant;
import com.eros.framework.constant.WXEventCenter;
import com.eros.framework.http.okhttp.cookie.store.PersistentCookieStore;
import com.eros.framework.manager.ManagerFactory;
import com.eros.framework.manager.impl.FileUpdownloaderManager;
import com.eros.framework.manager.impl.ImageManager;
import com.eros.framework.manager.impl.ModalManager;
import com.eros.framework.manager.impl.ParseManager;
import com.eros.framework.manager.impl.PersistentManager;
import com.eros.framework.manager.impl.dispatcher.DispatchEventManager;
import com.eros.framework.model.DownloadFileBean;
import com.eros.framework.model.ScanImageBean;
import com.eros.framework.model.UploadFileBean;
import com.eros.framework.model.UploadImageBean;
import com.eros.framework.model.UploadResultBean;
import com.eros.framework.model.WeexEventBean;
import com.eros.framework.utils.JsPoster;
import com.eros.framework.utils.PermissionUtils;
import com.eros.wxbase.EventGate;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Reader;
import com.google.zxing.common.HybridBinarizer;
import com.squareup.otto.Subscribe;
import com.taobao.weex.bridge.JSCallback;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import okhttp3.Cookie;
import okhttp3.HttpUrl;
import static android.content.Context.DOWNLOAD_SERVICE;
/**
* Created by roger on 2019/2/1.
*/
public class EventFile extends EventGate {
private JSCallback mPickCallback;
private Context mUploadContext;
@Override
public void perform(Context context, WeexEventBean weexEventBean, String type) {
String params = weexEventBean.getJsParams();
if (WXEventCenter.EVENT_FILE_DOWNLOAD.equals(type)) {
download(params, context, weexEventBean.getJscallback());
}
else if (WXEventCenter.EVENT_FILE_UPLOAD.equals(type)) {
upload(params, context, weexEventBean.getJscallback());
}
}
public void upload(String json, Context context, JSCallback jsCallback) {
//Manifest.permission.READ_EXTERNAL_STORAGE 权限申请
if (!PermissionUtils.checkPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE)) {
return;
}
mPickCallback = jsCallback;
mUploadContext = context;
UploadFileBean bean = ManagerFactory.getManagerService(ParseManager.class).parseObject
(json, UploadFileBean.class);
ManagerFactory.getManagerService(DispatchEventManager.class).getBus().register(this);
FileUpdownloaderManager fileUpdownloaderManager= ManagerFactory.getManagerService(FileUpdownloaderManager.class);
fileUpdownloaderManager.pick(context,bean,Constant.FileConstants.FILE_PICKER);
}
public void download(String json, Context context, JSCallback jsCallback) {
DownloadFileBean bean = ManagerFactory.getManagerService(ParseManager.class).parseObject
(json, DownloadFileBean.class);
String fileName = bean.name;
String suffix = bean.suffix;
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(bean.url));
HashMap<String,String> headers= ManagerFactory.getManagerService(ParseManager.class).parseObject
(bean.headers, HashMap.class);
for(Map.Entry<String,String> e:headers.entrySet()){
request.addRequestHeader(e.getKey(),e.getValue());
}
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.removeSessionCookie();// 移除旧的[可以省略]
List<Cookie> cookies = new PersistentCookieStore(context).getCookies();
String cookieString= "";
for (int i = 0; i < cookies.size(); i++) {
Cookie cookie = cookies.get(i);
System.out.println(cookie.name() + ":" + cookie.value()+":"+cookie.domain()+":"+cookie.path());
if (cookie.matches(HttpUrl.parse(bean.url))) {
String value = cookie.name() + "=" + cookie.value();
System.out.println(value);
cookieString += (value + "; ");
cookieManager.setCookie(bean.url, value);
}
}
if(cookieString.length()>0){request.addRequestHeader("Cookie",cookieString);}
// 允许在计费流量下下载
request.setAllowedOverMetered(true);
// 允许媒体扫描,根据下载的文件类型被加入相册、音乐等媒体库
request.allowScanningByMediaScanner();
// 设置通知的显示类型,下载进行时和完成后显示通知
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
// 设置通知栏的标题,如果不设置,默认使用文件名
request.setTitle(fileName+"."+suffix);
// 设置通知栏的描述
request.setAllowedOverMetered(true);
// 允许该记录在下载管理界面可见
request.setVisibleInDownloadsUi(true);
// 允许漫游时下载
request.setAllowedOverRoaming(true);
// 允许下载的网路类型
//request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
// 设置下载文件保存的路径和文件名
request.setMimeType("application/octet-stream");
switch(suffix){
case "rar":
request.setMimeType("application/x-rar-compressed");
break;
case "zip":
request.setMimeType("application/zip");
break;
case "ppt":
request.setMimeType("application/vnd.ms-powerpoint");
break;
case "xls":
request.setMimeType("application/vnd.ms-excel");
break;
case "xlsx":
request.setMimeType("application/vnd.ms-excel");
break;
case "doc":
request.setMimeType("application/msword");
break;
case "docx":
request.setMimeType("application/msword");
break;
case "jpg":
request.setMimeType("image/jpeg");
break;
case "png":
request.setMimeType("image/png");
break;
case "gif":
request.setMimeType("image/gif");
break;
case "apk":
request.setMimeType("application/vnd.android.package-archive");
break;
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName+"."+suffix);
// //另外可选一下方法,自定义下载路径
// request.setDestinationUri();
// request.setDestinationInExternalFilesDir();
try{
final DownloadManager downloadManager = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
// 添加一个下载任务
long downloadId = downloadManager.enqueue(request);
//Toast.makeText(context, "正在下载,请稍后在通知中心查看", Toast.LENGTH_LONG).show();
JsPoster.postSuccess("success", jsCallback);
return;
}
catch (Exception e){
e.printStackTrace();
}
JsPoster.postFailed("fail",jsCallback);
}
@Subscribe
public void OnUploadResult(UploadResultBean uploadResultBean) {
if (uploadResultBean != null && mPickCallback != null) {
JsPoster.postSuccess(uploadResultBean.data, mPickCallback);
}
ModalManager.BmLoading.dismissLoading(mUploadContext);
ManagerFactory.getManagerService(DispatchEventManager.class).getBus().unregister(this);
mPickCallback = null;
ManagerFactory.getManagerService(PersistentManager.class).deleteCacheData(Constant
.FileConstants.UPLOAD_FILE_BEAN);
}
}
创建
public class UploadFileBean implements Serializable {
public String url;
public int maxCount; //最大可选择个数
public String params; //上传附带参数 json
public String headers;//请求头
public List<String> files; // 上传文件本地地址列表
public String suffix;//支持的文件后缀名(形如"pptx,docx,xls"的字符串)
}
创建
public class FileUpdownloaderManager extends Manager {
/**
* 选择多个文件上传
*
* @param context 上下文对象
* @param bean Js 返回的数据集合
*/
public void pick(final Context context, UploadFileBean bean, int requestCode) {
DefaultFileAdapter.getInstance().pickFile(context, bean,requestCode);
}
/**
* 上传多个文件
*
* @param items 选择文件集合
* @param bean uplaod 参数对象
*/
public void UpMultipleFileData(Context context, ArrayList<NormalFile> items, UploadFileBean
bean) {
DefaultFileAdapter.getInstance().UpMultipleFileData(context, items, bean);
}
}
创建
public class DefaultFileAdapter {
private static DefaultFileAdapter mInstance = new DefaultFileAdapter();
private DefaultFileAdapter() {
}
public static DefaultFileAdapter getInstance() {
return mInstance;
}
public void pickFile(final Context context, UploadFileBean bean, int requestCode) {
if (!checkPermission(context)) return;
Intent intent4 = new Intent(context, NormalFilePickActivity.class);
intent4.putExtra(Constant.MAX_NUMBER, bean.maxCount);
intent4.putExtra(NormalFilePickActivity.SUFFIX, bean.suffix.split(","));
PersistentManager persistentManager = ManagerFactory.getManagerService(PersistentManager
.class);
persistentManager.setCacheData(com.eros.framework.constant.Constant.FileConstants.UPLOAD_FILE_BEAN, bean);
((Activity) context).startActivityForResult(intent4, requestCode);
}
public void UpMultipleFileData(Context context, ArrayList<NormalFile> items, UploadFileBean
bean) {
ModalManager.BmLoading.showLoading(context, null, false);
ArrayList imagesFilrUrl = new ArrayList();
if (items != null && items.size() > 0) {
for (NormalFile item : items) {
imagesFilrUrl.add(item.getPath());
}
}
HashMap<String, String> uploadParams = null;
HashMap<String, String> heads = null;
if (bean != null) {
String params = bean.params;
ParseManager parseManager = ManagerFactory.getManagerService(ParseManager.class);
uploadParams = parseManager.parseObject(params, HashMap.class);
heads = parseManager.parseObject(bean.headers, HashMap.class);
}
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.removeSessionCookie();// 移除旧的[可以省略]
List<Cookie> cookies = new PersistentCookieStore(context).getCookies();
String cookieString= "";
for (int i = 0; i < cookies.size(); i++) {
Cookie cookie = cookies.get(i);
if (cookie.matches(HttpUrl.parse(bean.url))) {
String value = cookie.name() + "=" + cookie.value();
cookieString += (value + "; ");
cookieManager.setCookie(bean.url, value);
}
}
if(cookieString.length()>0){heads.put("Cookie",cookieString);}
AxiosManager axiosManager = ManagerFactory.getManagerService(AxiosManager.class);
String url = TextUtils.isEmpty(bean.url) ? Api.UPLOAD_URL : bean.url;
axiosManager.upload(url, imagesFilrUrl, uploadParams, heads);
}
/**
* 判断Sd卡是否挂载,是否有Sd卡权限
*/
private boolean checkPermission(Context context) {
PermissionManager permissionManager = ManagerFactory.getManagerService(PermissionManager
.class);
boolean hasPermisson = permissionManager.hasPermissions(context, Manifest.permission
.READ_EXTERNAL_STORAGE);
if (!hasPermisson) {
ModalManager.BmToast.toast(context, "读取sd卡存储权限未授予,请到应用设置页面开启权限!", Toast.LENGTH_SHORT);
}
return hasPermisson;
}
}
添加
public static final class FileConstants {
public static final String UPLOAD_FILE_BEAN = "upload_file_bean";
public static final int FILE_PICKER = 102;
}
创建
public class DownloadFileBean implements Serializable {
public String url;//下载地址
public String headers;//请求头
public String name;//文件名(不包含后缀名)
public String suffix;//后缀名
}
添加
/**
*选择文件 上传
*/
if(requestCode==REQUEST_CODE_PICK_FILE&&resultCode == RESULT_OK){
ArrayList<NormalFile> list = data.getParcelableArrayListExtra(RESULT_PICK_FILE);
UpMultipleFileData(list);
}
添加
/**
* 上传文件
*/
private void UpMultipleFileData(ArrayList<NormalFile> items) {
FileUpdownloaderManager fileUpdownloadManager = ManagerFactory.getManagerService(FileUpdownloaderManager
.class);
UploadFileBean bean = ManagerFactory.getManagerService
(PersistentManager.class).getCacheData
(Constant.FileConstants.UPLOAD_FILE_BEAN, UploadFileBean.class);
fileUpdownloadManager.UpMultipleFileData(this, items, bean);
}
新增
private void upload(String url, String filePath, Map<String, String> uploadParams,
Map<String, String> heads, StringCallback callback, String contentDispositionName) {
PostFormBuilder builder = OkHttpUtils.post().url(url).params(uploadParams).headers(heads);
builder.addFile(contentDispositionName, AppUtils.getFileName(filePath), new File
(filePath));
builder.build().execute(callback);
}
修改为
public void upload(String url, List<String> fileMap, Map<String, String> uploadParams,
Map<String, String> heads) {
if (fileMap == null) {
return;
}
UploadImageCallback callback = new UploadImageCallback(fileMap.size());
if (uploadParams.containsKey("ContentDispositionName")) {
String contentDispositionName = uploadParams.get("ContentDispositionName");
uploadParams.remove("ContentDispositionName");
for (String filePath : fileMap) {
upload(url, filePath, uploadParams, heads, callback, contentDispositionName);
}
} else {
for (String filePath : fileMap) {
upload(url, filePath, uploadParams, heads, callback);
}
}
}
修改为
private void upload(String url, String filePath, Map<String, String> uploadParams,
Map<String, String> heads, StringCallback callback) {
PostFormBuilder builder = OkHttpUtils.post().url(url).params(uploadParams).headers(heads);
builder.addFile("file", AppUtils.getFileName(filePath), new File(filePath));
builder.build().execute(callback);
}
添加
<module name="FileModule">com.eros.framework.extend.module.FileModule</module>
添加
case WXEventCenter.EVENT_FILE_UPLOAD:
case WXEventCenter.EVENT_FILE_DOWNLOAD:
reflectionClazzPerform("com.eros.framework.event.file.EventFile", context
, weexEventBean
, "", weexEventBean.getKey());
break;