上一篇文章我们讲了okhttp的cookiejar和webview的使用的android cookieManager。这个设计确实不好,为啥三方库就不能基于系统进行扩展呢?
我的分析如下:首先okhttp并不只适用于android开发,java web开发在跨应用也有大量的使用常景。而内置与android.jar包下面的CookieManager跟android系统结合的特殊性,使得okhttp有自己的一套cookie运行,与cookie的本质和机制是差不多的。
现实生活我们总能遇到奇奇怪怪,形形色色的需求。最近我就遇到了一个关于pdf的需求,android确实不太友好,webview也没有ios的webview那么功能丰富。绝大多数时候,我们只能通过一点一点的扩展。今天我便遇到了一个大坑!
我们有一个业务场景是接入老旧的OA系统,里面有一个页面上面有pdf等文档文件。要知道android内置的webview根本没有chrome那么强大,所以很多时候在pc上玩的六的东西,到手机全都翘辫子了!哈哈
所以我不得不开发一个pdf的插件来满足这个业务场景。
一开始我把pdf插件规划为以下几步!
1.webview拦截url,校验文件是文档类型,
2.根据url开始执行下载,保存到本地
3.使用地方放pdf查看库进行pdf加载
在不断的试错中,慢慢的把它们细分如下
1.webview拦截url,校验文件是文档类型,
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = String.valueOf(request.getUrl());
if (url.isEmpty()) {
return true;
}
if (!url.startsWith("http") && !url.startsWith("HTTP")) {
return true;
}
if(url.toLowerCase().endsWith(".pdf")){
return true;
}
view.loadUrl(url);
return true;
}
2.区分pdf和wps等文件
public static String getMIMETypeStr(String end) {
String type;
if (end.equals("pdf")) {
type = "application/pdf";
} else if (end.equals("m4a") || end.equals("mp3") || end.equals("mid") ||
end.equals("xmf") || end.equals("ogg") || end.equals("wav")) {
type = "audio/*";
} else if (end.equals("3gp") || end.equals("mp4")) {
type = "video/*";
} else if (end.equals("jpg") || end.equals("gif") || end.equals("png") ||
end.equals("jpeg") || end.equals("bmp")) {
type = "image/*";
} else if (end.equals("apk")) {
type = "application/vnd.android.package-archive";
} else if (end.equals("pptx") || end.equals("ppt")) {
type = "application/vnd.ms-powerpoint";
} else if (end.equals("docx") || end.equals("doc")) {
type = "application/vnd.ms-word";
} else if (end.equals("xlsx") || end.equals("xls")) {
type = "application/vnd.ms-excel";
}else if(end.equals("txt")){
type = "text/plain";
}else if(end.equals("html") || end.equals("htm")){
type = "text/html";
} else {
//如果无法直接打开,就跳出软件列表给用户选择
type = "*/*";
}
return type;
}
3.使用okhttp并把cookie信息同步到CookieJar接口的实现类中,
public class PersistenceCookieJar implements CookieJar {
List<Cookie> cache = new ArrayList<>();
WeakReference<Context> weakReference=null;
public PersistenceCookieJar(Context mApp) {
weakReference=new WeakReference<Context>(mApp);
}
//Http请求结束,Response中有Cookie时候回调
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
//内存中缓存Cookie
cache.addAll(cookies);
ArrayList<String> cookieList=new ArrayList<>();
for(Cookie cookie:cookies){
cookieList.add(cookie.name()+"="+cookie.value());
}
url.topPrivateDomain();
syncCookie(".yourhost.com",cookieList);
}
/**
* 同步cookie
*
* @param url 地址
* @param cookieList 需要添加的Cookie值,以键值对的方式:key=value
*/
private void syncCookie(String url, ArrayList<String> cookieList) {
CookieSyncManager.createInstance(weakReference.get());
android.webkit.CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.removeAllCookie();
cookieManager.removeSessionCookie();
if (cookieList != null && cookieList.size() > 0) {
for (String cookie : cookieList) {
cookieManager.setCookie(url, cookie);
cookieManager.setCookie("yourhost.com", cookie);
}
}
String cookies = cookieManager.getCookie(url);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.flush();
} else {
CookieSyncManager.getInstance().sync();
}
}
//Http发送请求前回调,Request中设置Cookie
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
String urlString = url.toString();
String cookiesString = CookieManager.getInstance().getCookie(urlString);
if (cookiesString != null && !cookiesString.isEmpty()) {
String[] cookieHeaders = cookiesString.split(";");
List<Cookie> cookies = new ArrayList<>(cookieHeaders.length);
for (String header : cookieHeaders) {
cookies.add(Cookie.parse(url, header));
}
return cookies;
}
return Collections.emptyList();
}
}
4.获取写权限,根据url开始执行下载,保存到本地
RxPermissions rxPermissions = null;
rxPermissions = new RxPermissions(this);
rxPermissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE).subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) {
if (aBoolean) {
} else {
// ToastUtil.showToast("无读写外部存储设备权限");
}
}
});
5.gzip的无法获取到contentlength问题解决
6.使用地方放pdf查看库进行pdf加载,使用pdf阅读库的完整特性
implementation(‘com.github.barteksc:android-pdf-viewer:3.2.0-beta.1’){
exclude group: ‘androidx.legacy’
exclude group: ‘androidx.core’
}
nightMode=getCurrentTime();
pdfView.fromFile(file)
.onPageChange(this)
.onPageError(this)
.scrollHandle(new DefaultScrollHandle(getContext()))
.onLoad(this)
.enableAnnotationRendering(true)
.defaultPage(defaultPage)//记住上次读到的页面
.nightMode(nightMode)//暗黑模式
.spacing(spacing) // 内部间距
.password(password)//设置密码
.fitEachPage(true)
.swipeHorizontal(swipeHorizontal)//设置水平滚动
.load();