最近操作WebView遇到的些許問題,記錄貼

又再一次給webView槓上了,APP內開一個入口加上一個H5界面,界面中有些許交互。本來很簡單的問題,估工期還是算上 開產品會時並沒有明確交互的功能點,所以要了兩天的時間。但是沒有想到簡單的問題,自己還是持續採坑。

首先加密,APP內登陸,傳遞給js 登陸信息。H5內容是一個PK活動,可能考慮到防止黑客惡意攻擊等問題,對於傳遞APP用戶信息做了加密處理。定製最終方案是 MD5( 時間戳分鐘級加鹽)+MD5+HmacSha256

這裏記錄下寫的一個工具:MD5( 時間戳分鐘級加鹽)+MD5+HmacSha256

public class Md5Utils {

    /**
     * 16位MD5加密
     * 實際是截取的32位加密結果的中間部分(8-24位)
     *
     * @param content
     * @return
     */
    public static String md5Decode16(String content) {
        return md5Decode32(content).substring(8, 24);
    }

    /**
     * 32位MD5加密
     *
     * @param content -- 待加密內容
     * @return
     */
    public static String md5Decode32(String content) {
        byte[] hash;
        try {
            hash = MessageDigest.getInstance("MD5").digest(content.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("NoSuchAlgorithmException", e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("UnsupportedEncodingException", e);
        }
        //對生成的16字節數組進行補零操作
        StringBuilder hex = new StringBuilder(hash.length * 2);
        for (byte b : hash) {
            if ((b & 0xFF) < 0x10) {
                hex.append("0");
            }
            hex.append(Integer.toHexString(b & 0xFF));
        }
        return hex.toString();
    }

    private static String hmacSha(String KEY, String VALUE, String SHA_TYPE) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(KEY.getBytes("UTF-8"), SHA_TYPE);
            Mac mac = Mac.getInstance(SHA_TYPE);
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(VALUE.getBytes("UTF-8"));

            byte[] hexArray = {
                    (byte) '0', (byte) '1', (byte) '2', (byte) '3',
                    (byte) '4', (byte) '5', (byte) '6', (byte) '7',
                    (byte) '8', (byte) '9', (byte) 'a', (byte) 'b',
                    (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'
            };
            byte[] hexChars = new byte[rawHmac.length * 2];
            for (int j = 0; j < rawHmac.length; j++) {
                int v = rawHmac[j] & 0xFF;
                hexChars[j * 2] = hexArray[v >>> 4];
                hexChars[j * 2 + 1] = hexArray[v & 0x0F];
            }
            return new String(hexChars);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static String hmacSha(Context context, String token) {
        String key = ((System.currentTimeMillis()) + "");// 時間搓
        String time = TimeUtilsJ.stampTomonth(key);  // 轉時間格式
        String month = null;
        try {
            month =( TimeUtilsJ.dateToLongMonth(time) / 1000 )+"";  // 轉分鐘
        } catch (ParseException e) {
            e.printStackTrace();
        }
        String mToken = token + "epk";
        String md51 = md5Decode32(mToken);
        String md52 = md5Decode32(md51);
        String sha = hmacSha(month, md52, "HmacSHA256");
        return sha;

    }


}

問題二:

傳遞參數,排除loadUrl  直接拼接,採用WebView 網絡接口攔截 POST請求,把參數拼接進請求頭中的形式。(但是最終由於一些問題,Android還是才用了直接拼接傳單)

遇到問題,無法把參數塞進請求頭 目前沒有解決,後續關注。

先把自己嘗試的過程記錄一下,爲以後填坑打基礎。

WebViewClient 提供很多有用的功能,這裏不做詳細說明,有興趣的可以自行百度。

這裏找到一篇具體講解的

我使用具體功能是攔截

shouldInterceptRequest

我對這個方法的理解,攔截WebView中加載的一切請求,get,post。可以return null 的情況是自己程序不處理,還是給WebView 自行處理,返回有數據,是自己處理接口,並可以把接口返還給WebView 呈現出來。

這個方法有兩個重載方法,

已經過時,Google 不推薦使用

public WebResourceResponse shouldInterceptRequest(WebView view, String url)

推薦使用

public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request)

就是這個方法, 讓我發愁了一天。

 

這個是過時的方法處理,由於網上都是這樣寫的,雖然沒有達到我想要的效果,不過還是記錄下

            @SuppressLint("NewApi")
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
                if (url.contains("")) {
                    URL urlStr = null;
                    try {
                        urlStr = new URL(url );
                        URLConnection rulConnection = urlStr.openConnection();
                        HttpURLConnection conn = (HttpURLConnection) rulConnection;
                        conn.setRequestProperty("Accept-Charset", "utf-8");
                        conn.setRequestProperty("contentType", "utf-8");
                        conn.setRequestMethod("POST");
                        // Read input
                        String charset = conn.getContentEncoding() != null ? conn.getContentEncoding() : Charset.defaultCharset().displayName();
                        String mime = conn.getContentType();
                        InputStream isContents = conn.getInputStream();
                        StringBuilder sb = new StringBuilder();
                        String s; // 依次循環,至到讀的值爲空
                        BufferedReader reader = new BufferedReader(new InputStreamReader(isContents, "UTF-8")); // 實例化輸入流,並獲取網頁代碼
                        while ((s = reader.readLine()) != null) {
                            sb.append(s);
                        }
                        isContents.close();

                        String str = sb.toString();
                        Log.e("----------------",str);
                        return new WebResourceResponse(mime, charset,
                                isContents);
                    } catch (Exception e) {
                        e.printStackTrace();
                        return null;
                    }
                } else {
                    return super.shouldInterceptRequest(view, url);
                }
            }

 

            @SuppressLint("NewApi")
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {
                if (request.getUrl().toString().contains("")) {
                    request.getRequestHeaders().put("token", "");
                    request.getRequestHeaders().put("isApp", "");
                    Log.e("-----------------", request.getRequestHeaders() + "\n" + request.getUrl() + "\n" + request.getMethod());
                    return shouldInterceptRequest(view, request);
                }
                return super.shouldInterceptRequest(view, request);
            }

理論上這樣編寫,應該是可以解決我遇到的問題,從代碼結構上,很直觀的感覺是拿到 request的請求,然後把自己需要拼接的參數放進request中,然後在把請求轉給 shouldInterceptRequest 進行處理, 從中轉前 打印,request 也顯示已經拼接,

但是自己使用Fiddler 抓吧顯示,請求中並沒有加入參數。所以壓根無效。這裏我就鬱悶了,不知道怎麼處理,所以換了一種寫法

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
class WebResourceRequest1 implements WebResourceRequest {
    WebResourceRequest request;

    public WebResourceRequest1(WebResourceRequest request) {
        this.request = request;
    }

    @Override
    public Uri getUrl() {
        return Uri.parse(request.getUrl().toString());
    }

    @SuppressLint("NewApi")
    @Override
    public boolean isForMainFrame() {
        return request.isForMainFrame();
    }

    @Override
    public boolean isRedirect() {
        return true;
    }

    @SuppressLint("NewApi")
    @Override
    public boolean hasGesture() {
        return request.hasGesture();
    }

    @SuppressLint("NewApi")
    @Override
    public String getMethod() {
        Log.e("--------------", request.getMethod());

        return request.getMethod();
    }

    @SuppressLint("NewApi")
    @Override
    public Map<String, String> getRequestHeaders() {
        Map<String, String> map = request.getRequestHeaders();
        map.put("token", "");
        map.put("isApp", "");
        Log.e("--------------", "進入map");
        return map;
    }
}

依然無效。

然後自己開始Goole ,沒有找到任何有效的解決辦法,所以大神們,請求你們的幫助,

 

記錄需求:移動端加載WebView ,H5生命週期一起動就 post一個後端接口,請求用戶數據。而我要攔截的就是這個post 因爲前段請求這個接口的時候並沒有放入token ,需要移動端添加token,

按照IOS 說法 中間人模式(這裏我要吐槽 - 碰到一個時時刻刻要顯示自己很優秀的同事,我很無奈。我一直覺得,開發之間特別是我們這種兩端沒有任何利益糾葛,你好我好大家好,誰沒有一點採坑的經歷,但是你就是非要搞得全公司皆知,這個方案我進行不了等等云云的。)就我們這個app,雖然目前是做活動,但是被黑客攻擊的機率感覺就像中大獎一樣,並且傳遞token經過加密處理了。破解收益和付出完全不成正比。

好了前面吐槽,誰讓自己嘴皮子不利索,被懟的體無完膚,承認自己不懂還不行。這塊有空專研下,目前還是抓緊把任務完成-

 

抽空記錄

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章