Androidは4.4からWebViewがWebKitベースのものからChromeベースのものに変わりました。
もちろん一部仕様も変更されています。
例えばjavascriptの実行方法がloadUrl
メソッドからevaluateJavascript
メソッドに変わってしまっているので、両方対応しようとするとちょいとばかしダサいことになります。
if(Build.VERSION.SDK_INT < 19){
webView.loadUrl("javascript:alert('ダサい')");
}else{
webView.evaluateJavascript("alert('ダサい')", null);
}
また4.3以前の脆弱性サポートは既に打ち切られています。恐いのなんのって。
そこでいろいろ調べて見つけたのがCrosswalkというWebViewエンジン。
Androidアプリに組み込むことでバージョンに依存しないWebviewの実装・動作が可能になる。
素敵だからこいつを使ってみたよ。
そしてバッチリまとまった参考記事が少なかったのでまとめてみたよ。
1.XWalkViewをインストール
Mavenリポジトリを使うためbuild.gradle
に以下2つを追加する。
// 追加①
repositories {
maven {
url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'
}
}
// 追加②
compile 'org.xwalk:xwalk_core_library:20.50.533.12'
追加後のbuild.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "com.sample.hello"
minSdkVersion 23
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
// 追加①
repositories {
maven {
url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
// 追加②
compile 'org.xwalk:xwalk_core_library:20.50.533.12'
}
とっても簡単
2.XWalkViewを配置
WebView
の代わりにorg.xwalk.core.XWalkView
を対象のレイアウトに配置する
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.sample.hello.MainActivity">
<org.xwalk.core.XWalkView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
とっても簡単
5.AndroidManifestにpermissionを追加
<uses-permission android:name="android.permission.INTERNET"/>
追加後のAndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sample.hello">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
4.ActivityからXWalkViewを操作
package com.sample.hello;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import org.xwalk.core.XWalkResourceClient;
import org.xwalk.core.XWalkView;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
// XWalkViewに登録するResourceClient
private class ResourceClient extends XWalkResourceClient {
ResourceClient(XWalkView view) {
super(view);
}
// XWalkViewのロード完了通知
@Override
public void onLoadFinished(XWalkView view, String url) {
super.onLoadFinished(view, url);
// 描画後にグローバルに定義されたjavascript関数をコール
xWalkView.evaluateJavascript("onLoaded();", null);
}
// Location変更通知
@Override
public boolean shouldOverrideUrlLoading(XWalkView view, String url) {
// URLを使って値の受け渡しを行う
if (url.contains("app-api://")) {
// 'true'を返した場合Locationの変更がキャンセルされる
return true;
}
// 'false'を返した場合Locationの変更が続行される
return false;
}
}
private XWalkView xWalkView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// XWalkViewを取得
xWalkView = (XWalkView) findViewById(R.id.webView);
// XWalkViewから通知を受け取るためのXWalkResourceClient継承クラスをset
xWalkView.setResourceClient(new ResourceClient(xWalkView));
// loadメソッドに'Map<String, String>'を渡すことでリクエストヘッダーにフィールドを追加することができる
Map<String, String> additionalHttpHeaders = new HashMap<>();
additionalHttpHeaders.put("mobileAppAuth", "3f7d22402f6ac375bf1168c3ef5d8f08");
//localhostはアクセスできないのでローカルサーバーで開発中は自分のIPアドレス,ポートを指定してね
xWalkView.load("http://192.168.0.0:8000/gacha", null, additionalHttpHeaders);
//***********************************************************
// ここでグローバルに定義されたjavascript関数をコールしても
// `is not defined エラーで怒られます`
//***********************************************************
// xWalkView.evaluateJavascript("onLoaded();", null);
}
@Override
protected void onPause() {
super.onPause();
if (xWalkView != null) {
xWalkView.pauseTimers();
xWalkView.onHide();
}
}
@Override
protected void onResume() {
super.onResume();
if (xWalkView != null) {
xWalkView.resumeTimers();
xWalkView.onShow();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (xWalkView != null) {
xWalkView.onDestroy();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (xWalkView != null) {
xWalkView.onActivityResult(requestCode, resultCode, data);
}
}
@Override
protected void onNewIntent(Intent intent) {
if (xWalkView != null) {
xWalkView.onNewIntent(intent);
}
}
}
XWalkResourceClient
にはこれだけOverride可能なメソッドがあるのでプログレスバー出したり等いろいろな拡張ができそう。
return | メソッド名 |
---|---|
void | onLoadFinished(XWalkViewInternal view, String url) |
void | onLoadStarted(XWalkViewInternal view, String url) |
void | onProgressChanged(XWalkViewInternal view, int progressInPercent) |
void | onReceivedLoadError(XWalkViewInternal view, int errorCode, String description, String failingUrl) |
WebResourceResponse | shouldInterceptLoadRequest(XWalkView view, String url) |
WebResourceResponse | shouldInterceptLoadRequest(XWalkViewInternal view, String url) |
5.実行
はい、出ました。

最後に
XWalkView、WebView関連の記事を探していたらevaluateJavascriptメソッドでグローバルに定義した関数をコールすることができますよ
という旨の記載が多々出てくるが、騙されてはいけない。
実際はWebViewのロード完了後以降でないとコールできないのだが、その点には一切触れていないものが多かったので注意されたし。これだけで3時間はハマる(ハマった)。