简书链接:顶象安全键盘webview的研究 文章字数:520,阅读全文大约需要2分钟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.dingxiang.mobile.keyboard.safe; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.content.LocalBroadcastManager; import android.widget.RelativeLayout; import com.dingxiang.mobile.keyboard.DXSafeEditView; import com.dingxiang.mobile.keyboard.util.KeyBoardJniUtils; import com.dingxiang.mobile.keyboard.util.a; public class DXkbActivity extends Activity { private Context a; private RelativeLayout b; private a c; private DXSafeEditView d; private String e; private int f; public DXkbActivity() { } private void a() { this.b = new RelativeLayout(this); this.b.setGravity(80); this.b.setBackgroundColor(0); } protected void onCreate(@Nullable Bundle var1) { super.onCreate(var1); this.getWindow().addFlags(8192); this.requestWindowFeature(1); this.a = this; this.a(); this.setContentView(this.b); this.e = this.getIntent().getExtras().getString("SAFE_KEYBOARD_NAME", ""); this.f = this.getIntent().getExtras().getInt("SAFE_KEYBOARD_ID", 0); this.d = new DXSafeEditView(this, this.e, this.f); this.d.setVisibility(8); this.c = new a(this); this.c.a(new com.dingxiang.mobile.keyboard.util.a.a() { public void a() { DXkbActivity.this.finish(); } public void b() { DXkbActivity.this.d(); } }); this.c.a(this.d); this.b(); } private void b() { Intent var1 = new Intent(); var1.setAction("DX.ACTION.HANDLE_" + this.e + "_" + this.f); var1.putExtra("SAFE_HANDLE", "OPEN_INFO"); LocalBroadcastManager.getInstance(this).sendBroadcast(var1); } private void c() { Intent var1 = new Intent(); var1.setAction("DX.ACTION.HANDLE_" + this.e + "_" + this.f); var1.putExtra("SAFE_HANDLE", "CLOSE_INFO"); LocalBroadcastManager.getInstance(this).sendBroadcast(var1); } private void d() { Intent var1 = new Intent(); var1.setAction("DX.ACTION.HANDLE_" + this.e + "_" + this.f); var1.putExtra("SAFE_HANDLE", "UPDATE_INFO"); var1.putExtra("SAFE_STR_LENGTH", KeyBoardJniUtils.a().b()); LocalBroadcastManager.getInstance(this).sendBroadcast(var1); } protected void onStart() { super.onStart(); if (!this.c.b()) { this.c.a(this.d); } } protected void onPause() { super.onPause(); this.overridePendingTransition(0, 0); } protected void onDestroy() { super.onDestroy(); this.c(); } public void onBackPressed() { super.onBackPressed(); this.c.a(); this.finish(); } }
DXJavascriptBridge
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.dingxiang.mobile.keyboard; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.support.v4.content.LocalBroadcastManager; import android.webkit.JavascriptInterface; import android.webkit.WebView; import android.widget.Toast; import com.dingxiang.mobile.keyboard.safe.DXkbActivity; import com.dingxiang.mobile.keyboard.util.KeyBoardJniUtils; import com.dingxiang.mobile.keyboard.util.b; import java.util.Set; import java.util.TreeSet; public class DXJavascriptBridge { private final int KBD_MAX_NUM = 8; private Context context; private Set<String> saKbdName; private WebView webView; private int id; private String name; private String type; DXJavascriptBridge.a mSafeEditViewReceiver; private static final String showChar = "*"; public DXJavascriptBridge(Context var1, WebView var2) { this.context = var1; this.webView = var2; this.saKbdName = new TreeSet(); this.webView.setDescendantFocusability(393216); } public void onDestory() { } private void setText(final String var1) { this.webView.post(new Runnable() { public void run() { DXJavascriptBridge.this.webView.loadUrl("javascript:setText('" + DXJavascriptBridge.this.name + "','" + var1 + "')"); } }); } private String getCharStr(int var1) { StringBuilder var2 = new StringBuilder(); for(int var3 = 0; var3 < var1; ++var3) { var2.append("*"); } return var2.toString(); } @JavascriptInterface public void requreFocus(String var1, String var2, String var3) { this.type = var2; this.name = var1; this.id = 88688; Toast.makeText(this.context, var1 + " _ " + var2 + "_" + var3, 1).show(); b.a(this.context); Intent var4 = new Intent(this.context, DXkbActivity.class); var4.putExtra("SAFE_KEYBOARD_NAME", var1); var4.putExtra("SAFE_KEYBOARD_ID", this.id); this.registerReiceiver(); this.context.startActivity(var4); } private void registerReiceiver() { if (null == this.mSafeEditViewReceiver) { String var1 = "DX.ACTION.HANDLE_" + this.name + "_" + this.id; this.mSafeEditViewReceiver = new DXJavascriptBridge.a(null); IntentFilter var2 = new IntentFilter(); var2.addAction(var1); LocalBroadcastManager.getInstance(this.context).registerReceiver(this.mSafeEditViewReceiver, var2); } } @JavascriptInterface public void requestBlur(String var1, String var2, String var3) { b.a(this.context); } @JavascriptInterface public String getValue(String var1, String var2, String var3) { b.a(this.context); return KeyBoardJniUtils.a().c(); } private void onCloseActivity() { if (this.mSafeEditViewReceiver != null) { LocalBroadcastManager.getInstance(this.context).unregisterReceiver(this.mSafeEditViewReceiver); this.mSafeEditViewReceiver = null; } } private class a extends BroadcastReceiver { private a() { } public void onReceive(Context var1, Intent var2) { String var3 = "DX.ACTION.HANDLE_" + DXJavascriptBridge.this.name + "_" + DXJavascriptBridge.this.id; if (var2.getAction().equals(var3)) { String var4 = var2.getExtras().getString("SAFE_HANDLE", ""); if (!var4.equals("OPEN_INFO")) { if (var4.equals("CLOSE_INFO")) { DXJavascriptBridge.this.onCloseActivity(); } else if (var4.equals("UPDATE_INFO")) { int var5 = var2.getExtras().getInt("SAFE_STR_LENGTH", 0); DXJavascriptBridge.this.setText(DXJavascriptBridge.this.getCharStr(var5)); } } } } } }
js代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Carson_Ho</title> <body> <input type="text" id="dx_id" name="yourpw" value="" readonly onfocus="requreFocus(this)" onblur="requestBlur(this)"/> <button value="getValue" onclick="getValue()"/> </body> // JS代码 <script> // Android需要调用的方法 function callJS(){ alert("Android调用了JS的callJS方法"); } function clientType(){ if(stristr($_SERVER['HTTP_USER_AGENT'],'Android')) { return "android"; }else if(stristr($_SERVER['HTTP_USER_AGENT'],'iPhone')){ return "ios"; }else{ return 'other'; } } function requreFocus(e){ <!--alert("Android调用了JS的callJS方法");--> e.blur(); window.DXobject.requreFocus(e.name , e.type , e.id); } function requestBlur(e){ <!--alert("Android调用了JS的callJS方法");--> window.DXobject.requestBlur(e.name , e.type , e.id); } function setText(name , str){ <!--alert(str);--> window.document.getElementsByName(name)[0].value = str; } function getValue(){ <!--alert(str);--> var e = window.document.getElementById("dx_id"); var _name = e.name; var _type = e.type; var _id = e.id; var value = window.DXobject.getValue(_name , _type , _id); alert(value); <!--window.document.getElementsByName(name)[0].value = str;--> } </script> </head> </html>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 package com.dingxiang.app.keyboard; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.View; import android.webkit.JsResult; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import com.dingxiang.mobile.keyboard.DXJavascriptBridge; /** * weaiken * 2018/6/25 **/ public class WebActivity extends Activity { WebView mWebView; Context mContext; @SuppressLint("JavascriptInterface") @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_web); mWebView = findViewById(R.id.webview); mContext = this; WebSettings settings = mWebView.getSettings(); //默认是false 设置true允许和js交互 settings.setJavaScriptEnabled(true); // WebSettings.LOAD_DEFAULT 如果本地缓存可用且没有过期则使用本地缓存,否加载网络数据 默认值 // WebSettings.LOAD_CACHE_ELSE_NETWORK 优先加载本地缓存数据,无论缓存是否过期 // WebSettings.LOAD_NO_CACHE 只加载网络数据,不加载本地缓存 // WebSettings.LOAD_CACHE_ONLY 只加载缓存数据,不加载网络数据 //Tips:有网络可以使用LOAD_DEFAULT 没有网时用LOAD_CACHE_ELSE_NETWORK settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //开启 DOM storage API 功能 较大存储空间,使用简单 settings.setDomStorageEnabled(true); //设置数据库缓存路径 存储管理复杂数据 方便对数据进行增加、删除、修改、查询 不推荐使用 settings.setDatabaseEnabled(true); settings.setJavaScriptEnabled(true); settings.setJavaScriptCanOpenWindowsAutomatically(true); DXJavascriptBridge jsInterface = new DXJavascriptBridge(mContext, mWebView); mWebView.addJavascriptInterface(jsInterface, "DXobject"); mWebView.loadUrl("file:///android_asset/javascript.html"); // 由于设置了弹窗检验调用结果,所以需要支持js对话框 // webview只是载体,内容的渲染需要使用webviewChromClient类去实现 // 通过设置WebChromeClient对象处理JavaScript的对话框 //设置响应js 的Alert()函数 mWebView.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { AlertDialog.Builder b = new AlertDialog.Builder(mContext); b.setTitle("Alert"); b.setMessage(message); b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }); b.setCancelable(false); b.create().show(); return true; } } ); } public void click(View view) { mWebView.post(new Runnable() { @Override public void run() { // 注意调用的JS方法名要对应上 // 调用javascript的callJS()方法 mWebView.loadUrl("javascript:callJS()"); } }); } }
定义object对象。
1 2 DXJavascriptBridge jsInterface = new DXJavascriptBridge(mContext, mWebView); mWebView.addJavascriptInterface(jsInterface, "DXobject");
js调用对象
1 2 3 4 5 6 7 8 9 10 function getValue(){ <!--alert(str);--> var e = window.document.getElementById("dx_id"); var _name = e.name; var _type = e.type; var _id = e.id; var value = window.DXobject.getValue(_name , _type , _id); alert(value); <!--window.document.getElementsByName(name)[0].value = str;--> }