原则上Java 本身不支持脚本计算,早期通过ScriptManager或者J2V8支持脚本计算,但在Android中阉割了此部分功能,因此,为了能进行脚本计算,我们需要特别封装
import android.content.Context;import android.database.DataSetObserver;import android.graphics.Bitmap;import android.os.Build;import android.os.Handler;import android.os.Message;import android.util.Log;import android.webkit.ConsoleMessage;import android.webkit.JsResult;import android.webkit.ValueCallback;import android.webkit.WebChromeClient;import android.webkit.WebResourceError;import android.webkit.WebResourceRequest;import android.webkit.WebResourceResponse;import android.webkit.WebSettings;import android.webkit.WebView;import android.webkit.WebViewClient;import org.json.JSONException;import org.json.JSONObject;/** * Created by Noah on 2016/1/23. */public class JavaScriptManager implements Handler.Callback{ //计算引擎 private WebView jsEngine; //计算结果回调 private Handler.Callback mCallback; //判断页面是否加载完成 private boolean isLoadFinished; //表示加载完成 public final static int STATE_FINISHED = 200; //返回正确结果 public final static int STATE_RESULT_OK = 100; //计算出错 public final static int STATE_RESULT_FAILED = -100; //加载开始 public final static int STATE_STARTING = 300; private JavaScriptManager(Context context,Handler.Callback callback) { jsEngine = new WebView(context); initJsEngine(); this.mCallback = callback; } public static JavaScriptManager newInstance(Context context,Handler.Callback callback) { return new JavaScriptManager(context,callback); } private void initJsEngine() { if(jsEngine!=null) { WebSettings settings = jsEngine.getSettings(); settings.setCacheMode(WebSettings.LOAD_NO_CACHE); settings.setAppCacheEnabled(false); settings.setJavaScriptCanOpenWindowsAutomatically(false); settings.setSupportMultipleWindows(false); settings.setSaveFormData(false); settings.setGeolocationEnabled(false); settings.setJavaScriptEnabled(true); settings.setSupportZoom(false); settings.setDefaultTextEncodingName("utf-8"); jsEngine.setWebChromeClient(new JsEngineChromeClient(this)); jsEngine.setWebViewClient(new JsEngineWebClient(this)); } } @Override public boolean handleMessage(Message msg) { if(msg!=null) { if(msg.what==STATE_RESULT_OK) { return mCallback.handleMessage(msg); } else if(msg.what==STATE_FINISHED) { isLoadFinished = true; }else if(msg.what==STATE_STARTING){ isLoadFinished = false; }else{ Log.e("JavaScriptManager","ErrorCode="+msg.what+"description="+(String)msg.obj); //防止脚本出错之后影响程序运行,有必要重新刷新 if(msg.what==STATE_RESULT_FAILED) { jsEngine.reload(); } return mCallback.handleMessage(msg); } } return false; } public void loadWebData(String html) { if(isLoadFinished && jsEngine!=null) { jsEngine.loadData(html,"text/html;charset=utf-8","utf-8"); } } private String stringByEvaluatingJavaScriptFromString(String script){ try { Field field_webviewcore = android.webkit.WebView.class.getDeclaredField("mWebViewCore"); field_webviewcore.setAccessible(true); Object obj_webviewcore = field_webviewcore.get(jsEngine); Field field_BrowserFrame = obj_webviewcore.getClass().getDeclaredField("mBrowserFrame"); field_BrowserFrame.setAccessible(true); Object obj_frame = field_BrowserFrame.get(obj_webviewcore); Method method_stringByEvaluatingJavaScriptFromString = obj_frame.getClass().getMethod("stringByEvaluatingJavaScriptFromString", new Class[] { java.lang.String.class }); Object obj_value = method_stringByEvaluatingJavaScriptFromString.invoke(obj_frame, new Object[] { script }); return String.valueOf(obj_value); } catch(Exception e) { e.printStackTrace(); jsEngine.loadUrl(script); } return null;} public void executeScript(String script) { if(jsEngine!=null) { if(Build.VERSION.SDK_INT>=19) { jsEngine.evaluateJavascript(script, new ValueCallback() { @Override public void onReceiveValue(String message) { Message msg = new Message(); try { JSONObject json = new JSONObject(message); msg.what = json.optInt("code",STATE_RESULT_OK); msg.obj = json.optString("result",""); } catch (JSONException e) { e.printStackTrace(); msg.what = -STATE_RESULT_FAILED; } JavaScriptManager.this.handleMessage(msg); } }); }else{ stringByEvaluatingJavaScriptFromString("javascript:"+script); } } } private static class JsEngineWebClient extends WebViewClient{ public Handler.Callback callback; public JsEngineWebClient(Handler.Callback callback){ this.callback = callback; } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); Message msg = new Message(); msg.what = errorCode; msg.obj = description; callback.handleMessage(msg); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); Message msg = new Message(); msg.what = STATE_FINISHED; msg.obj = "finished"; callback.handleMessage(msg); } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); Message msg = new Message(); msg.what = STATE_STARTING; msg.obj = "finished"; callback.handleMessage(msg); } } private static class JsEngineChromeClient extends WebChromeClient{ public Handler.Callback callback; public JsEngineChromeClient(Handler.Callback callback){ this.callback = callback; } @Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { if (consoleMessage.messageLevel()==ConsoleMessage.MessageLevel.ERROR) { Log.e("JavaScriptManager" + consoleMessage.lineNumber(), consoleMessage.message()); }else if(consoleMessage.messageLevel()==ConsoleMessage.MessageLevel.WARNING){ Log.w("JavaScriptManager"+consoleMessage.lineNumber(),consoleMessage.message()); }else{ Log.i("JavaScriptManager"+consoleMessage.lineNumber(),consoleMessage.message()); } return super.onConsoleMessage(consoleMessage); } @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { result.confirm(); Message msg = new Message(); try { JSONObject json = new JSONObject(message); msg.what = json.optInt("code",STATE_RESULT_OK); msg.obj = json.optString("result",""); } catch (JSONException e) { e.printStackTrace(); msg.what = STATE_RESULT_FAILED; } callback.handleMessage(msg); return true; } }}
当然,我们还需要初始化,以保证我们的脚本可以更加健壮
public class ScriptFactory { public String createScript() { StringBuilder sb = new StringBuilder(); sb.append(""); sb.append("\r\n"); sb.append(""); sb.append("\r\n"); sb.append(""); sb.append("\r\n"); sb.append(" "); sb.append("\r\n"); sb.append(" "); sb.append("\r\n"); sb.append("Javascript Engine "); sb.append("\r\n"); sb.append(""); sb.append("\r\n"); sb.append(""); sb.append("\r\n"); sb.append("