Android中混合式開發(fā)的過程中丙笋,加載html頁面的時(shí)候,如果該頁面加載的資源比較多央勒,比如css不见,js,公用的圖片資源等崔步,就會(huì)導(dǎo)致該頁面加載緩慢稳吮,耗費(fèi)大量的流量,這對(duì)流量限制的客戶端來說井濒,用戶體驗(yàn)非常不好灶似,所以就需要將這些資源存放在APP中列林,待APP啟動(dòng)的時(shí)候,直接從本地加載這些公用的資源酪惭。(本方法只針對(duì)html文件從網(wǎng)絡(luò)上獲认3铡)
方式一:使用loadDataBaseUrl的方式
當(dāng)從網(wǎng)絡(luò)上加載的html頁面中包含“file:///……”
或者“content://packagename/……”
(content://……這種需要重寫Provider)這樣的路徑時(shí),可以直接使用loadDataWithBaseURL("file:///",htmlSource,"text/html;charset=utf-8",null,null)
重新加載春感,其中htmlSource
為網(wǎng)頁源代碼砌创。
參考"stackoverflow" Load HTML data into WebView, referencing local images?
activity中示例代碼
/**
* 加載html文件
* @param path 文件路徑
*/
private void loadHtml(final String path){
new Thread(new Runnable() {
@Override
public void run() {
try {
URL url = new URL(path.trim());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true); //允許輸入流,即允許下載
conn.setDoOutput(true); //允許輸出流鲫懒,即允許上傳
conn.setUseCaches(false); //不使用緩沖
conn.setRequestMethod("GET"); //使用get請(qǐng)求
if (conn.getResponseCode() == 200){
InputStream inputStream = conn.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = -1;
while((length = inputStream.read(buffer))!=-1){
baos.write(buffer,0,length);
baos.flush();
}
final String htmlSource = baos.toString();
runOnUiThread(new Runnable(){
@Override
public void run() {
//重寫
mWebView.loadDataWithBaseURL("file:///",htmlSource,"text/html;charset=utf-8",null,null);
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
H5示例代碼(該h5頁面是放在服務(wù)器上面的)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>H5調(diào)用Native“獲取地理位置”與“拍照上傳“的功能</title>
<link rel="stylesheet">
<!--放在assets目錄下面的css.css文件-->
<link href="file:///android_asset/css.css" rel="stylesheet">
</head>
<body>
<!-- 用css設(shè)置樣式嫩实,看通過這種方式是否能加載本地assets目錄中的css文件 -->
<h4 class="text-left">H5調(diào)用安卓“拍照上傳“的功能:</h4>
<!-- 放在SDCARD中的圖片 -->
<img src="file:///storage/emulated/0/newCrop.jpg" alt="" class="img-responsive img-thumbnail">
<!-- 放在SDCARD中的圖片 packagename為包名-->
<img src="content://packagename/storage/emulated/0/newCrop.jpg" alt="本地圖片"/>
</body>
</html>
css文件內(nèi)容如下
.text-left{background-color:#f00}
正常結(jié)果如上所示。
方式二:使用ContentProvider的方式
使用content://方式訪問本地資源的時(shí)候窥岩,需要重寫ContentProvider,簡(jiǎn)單代碼如下:
public class LoadPicProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
@Nullable
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
URI filePath = URI.create( "file://" + uri.getPath() );
File file = new File( filePath );
ParcelFileDescriptor parcel = null;
try {
parcel = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return parcel;
}
}
然后在mainfest中進(jìn)行注冊(cè)
<provider android:authorities="packagename" android:name=".LoadPicProvider">
</provider>
方式三:使用Base64的方式
參考鏈接 StackOverflow Embedding Base64 Images
示例代碼
ByteArrayOutputStream out = new ByteArrayOutputStream();
//TODO 文件讀取需要線程操作
FileInputStream fis = new FileInputStream(imageCropUri.toString());
byte buff[] = new byte[1024];
int length = -1;
while((length = fis.read(buff))!= -1){
out.write(buff,0,length);
out.flush();
}
String fileBase64 = Base64.encodeToString(out.toByteArray(),Base64.NO_WRAP);
//將當(dāng)前的fileBase64傳到h5頁面中甲献,并設(shè)置到img上
js代碼
<img alt="Embedded Image" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA..." />
方式四:使用shouldInterceptRequest進(jìn)行文件資源的攔截
從API 11(Android 3.0)開始引入這個(gè)方法。shouldInterceptRequest這個(gè)回調(diào)可以通知主程序WebView處理的資源(css,js,image等)請(qǐng)求颂翼,并允許主程序進(jìn)行處理后返回?cái)?shù)據(jù)晃洒。如果主程序返回的數(shù)據(jù)為null,WebView會(huì)自行請(qǐng)求網(wǎng)絡(luò)加載資源朦乏,否則使用主程序提供的數(shù)據(jù)球及。注意這個(gè)回調(diào)發(fā)生在非UI線程中,所以進(jìn)行UI系統(tǒng)相關(guān)的操作是不可以的。
shouldInterceptRequest有兩種重載集歇。
- public WebResourceResponse shouldInterceptRequest (WebView view, String url) 從API 11開始引入桶略,API 21棄用
- public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request) 從API 21開始引入
所以在使用的時(shí)候语淘,最好兩者都要進(jìn)行重寫诲宇。
測(cè)試代碼如下
mWebView.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
String key = "http://localhost/";
WebResourceResponse response = null;
if (url.contains(key)) {
try {
String imgPath = url.replace(key,"");
imgPath = Uri.parse(imgPath).getPath();
InputStream localCopy = new FileInputStream(imgPath);
//當(dāng)前只針對(duì)圖片
response = new WebResourceResponse("image/png", "UTF-8", localCopy);
} catch (IOException e) {
e.printStackTrace();
}
}
return response;
}
});
注意:當(dāng)從本地相冊(cè)拍照完成后,圖片的uri可能是這樣的file:///storage/emulated/0/newCrop.jpg惶翻,如果這個(gè)url回調(diào)給 js是顯示不出來的姑蓝。因?yàn)閣ebview根本不會(huì)自動(dòng)加載。所以這個(gè)時(shí)候可以考慮在當(dāng)前地址上面添加http://……這樣這個(gè)url設(shè)置完成之后吕粗,才能夠正常的發(fā)出纺荧。
例如我得拍照產(chǎn)生的image的uri如下
<img src="file:///storage/emulated/0/newCrop.jpg" alt="" class="img-responsive img-thumbnail">
用攔截的方式顯示不出來,然后后我改為
<img src="http://localhost/file:///storage/emulated/0/newCrop.jpg" alt="" class="img-responsive img-thumbnail">
這樣在http請(qǐng)求發(fā)生的時(shí)候颅筋,會(huì)被shouldInterceptRequest
方法攔截
參看鏈接:
Webview加載本地圖片的方案對(duì)比