華爲系統更新後安裝了一個谷歌6月安全補丁的東西,然後之前寫的調h5頁面的部分就出現了問題,後臺查過發現是Android端調h5頁面時cookie沒能帶過去,導致了登錄失敗。於是對setCookie部分的代碼進行了調試,發現單步運行時只要在setCookie部分時多等一會頁面就可以正常打開,所以懷疑是異步的問題,先是在網上查了一通,說是這種情況可以讓程序多睡會,但是這種解決方法並沒有成功,而且覺得這麼寫代碼有點彆扭,於是就又查了一下設置Cookie部分的官方說明,發現 cookieManager.removeAllCookies其實是異步函數,之前寫代碼的人把他當同步用了,導致setCookie完成後,removeAllCookies函數才執行完的,把填進去的cookie又給移除了,所以導致了打開頁面的失敗。沒安補丁之前,可能是cookie都帶過去了,remove函數才執行完,安補丁後remov函數的運行速度提升了,但是具體原因不明,因爲查不到補丁的內容,總之無論如何,異步函數當同步使用是萬萬不能的。
以下是改之前錯誤的代碼,removeAllCookies被當成了同步函數使用
void fun(){
...
addCookies();
mWebview = (SystemWebView) appView.getView();
engine = (SystemWebViewEngine) appView.getEngine();
mWebview.setWebViewClient(new SystemWebViewClient(engine){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
...
});
}
private void addCookies() {
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
cookieManager.setAcceptCookie(true);
List<Cookie> cookieList = MainApp.getInstance().getGlobalState().getCookies();
for (Cookie cookie: cookieList){
String cookieString = cookie.name() + "=" + cookie.value();
cookieManager.setCookie(url, cookieString);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.flush();
} else {
CookieSyncManager.createInstance(this);
CookieSyncManager.getInstance().sync();
}
}
以下是改後的代碼,removeAllCookies()有一個完成後會在當前線程調用的方法,利用他remove完成後在set就沒問題了,而且addCookie()的調用被移進了onPageStarted之前,不然,之前那麼寫的話會先完成調用onPageStarted(),後完成addCookie()的調用,cookie依然不能設置成功
void fun(){
mWebview = (SystemWebView) appView.getView();
engine = (SystemWebViewEngine) appView.getEngine();
mWebview.setWebViewClient(new SystemWebViewClient(engine){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
addCookies();
super.onPageStarted(view, url, favicon);
}
...
});
}
private void addCookies() {
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.removeAllCookies(new ValueCallback<Boolean>() {
@Override
public void onReceiveValue(Boolean value) {
setCookie(cookieManager);
}
});
}else{
cookieManager.removeAllCookie();
setCookie(cookieManager);
}
}
void setCookie( CookieManager cookieManager){
List<Cookie> cookieList = MainApp.getInstance().getGlobalState().getCookies();
for (Cookie cookie: cookieList){
String cookieString = cookie.name() + "=" + cookie.value();
cookieManager.setCookie(url, cookieString);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.flush();
} else {
CookieSyncManager.createInstance(this);
CookieSyncManager.getInstance().sync();
}
}
這是removeAllCookies()方法的完整說明
/** * Removes all cookies. * <p> * This method is asynchronous. * If a {@link ValueCallback} is provided, * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current * thread's {@link android.os.Looper} once the operation is complete. * The value provided to the callback indicates whether any cookies were removed. * You can pass {@code null} as the callback if you don't need to know when the operation * completes or whether any cookies were removed, and in this case it is safe to call the * method from a thread without a Looper. * @param callback a callback which is executed when the cookies have been removed */ public abstract void removeAllCookies(ValueCallback<Boolean> callback);