カテゴリー
SugiBlog Webエンジニアのためのお役立ちTips

WebViewを使ったハイブリッドアプリの作成 [Android]

この記事は最終更新日から1年以上経過しています。

HTML5+JavaScriptを使ってスマホアプリを開発することもできます。
ネイティブとWebアプリの機能を兼ね備えた、俗にハイブリッドアプリと呼ばれるそうです。

ここで作成するのはハイブリッドというには簡単すぎるものですが、
触りとなるものです。

まず、メインとなるアクティビティを作成します。
サンプルですので、WebViewのみ表示するものとなっています。

public class SampleActivity extends Activity {

    private final int FC = ViewGroup.LayoutParams.FILL_PARENT;
    public static WebView web;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        LinearLayout linearLayout = new LinearLayout(this);
        linearLayout.setOrientation(1);

        setContentView(linearLayout);

        web = new WebView(this);
        linearLayout.addView(web, new LayoutParams(FC, FC));

        // JavaScriptを有効にする
        web.getSettings().setJavaScriptEnabled(true);

        // JavaScriptにAPIを追加する
        web.addJavascriptInterface(new JavaScriptObject(this), "myapi");

        // スクロールバーを非表示にする
        web.setHorizontalScrollBarEnabled(false);
        web.setVerticalScrollBarEnabled(false);

        // フォーカスを有効にする
        web.setFocusable(true);

        // assetsディレクトリに用意したHTMLを読み込み
        web.loadUrl("file:///android_asset/sample.html");
    }

}

29行目のフォーカスを有効にするというのはデフォルトで有効になっていますが、
敢えて明示的に有効にしています。
どういった場合に無効にするのかと言いますと、全画面表示のゲームを作成する場合等です。
無効にする場合は引数をfalseとします。

web.setFocusable(false);

更にその場合はスリープモードにしないようにもしておいたほうがよいでしょう。
onCreateの最後にでも記述しておきましょう。

// スリープモードにしないようにする
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

次に、JavaScriptのAPIとなるクラスを作成します。

class JavaScriptObject {

    Context context;

    JavaScriptObject(Context context) {
        this.context = context;
    }

    public void showToast(String message, String time) {
        boolean islong = time.equals("LONG");
        Toast toast = Toast.makeText(context, message,
                islong?Toast.LENGTH_LONG:Toast.LENGTH_SHORT);
        toast.show();
    }

    public void openweb(String url) {
        Intent i;

        try{

            //ブラウザの起動
            i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            context.startActivity(i);

        } catch (Exception e) {

            e.printStackTrace();

        }
    }

    public void openweb2(String url) {

        try{

            SampleActivity.web.loadUrl(url);

        } catch (Exception e) {

            e.printStackTrace();

        }
    }

    // アラート表示
    public void showAlert(final String msg) {
        new AlertDialog.Builder(context)
            .setTitle("アラート表示")
            .setMessage(msg)
            .setPositiveButton("OK", null)
            .show();
    }

}

そして、プロジェクトのassetsディレクトリにHTMLを作成します。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, height=device-height, user-scalable=no">
<meta name="format-detection" content="telephone=no">
<link rel="stylesheet" type="text/css" href="./css/sample.css" media="screen">
<script type="text/javascript" src="./js/sample.js"></script>
</head>
<body>

<p>
    <input id="sample_button1" type="button" value="トースト表示">
</p>

<p>
    テキストボックスに入力したテキストをアラート表示
    <input id="msg" type="text" size="20" name="msg" value=""><br>
    <input id="sample_button2" type="button" value="アラート表示">
</p>

<p>
    <a href="./sample2.html">同じassets内のsample2.htmlを開く</a>
</p>

<p>
    <input id="sample_button3" type="button" value="ブラウザアプリでYahoo!を開く"><br>
    通常リンクでも同様に開きます <a href="http://www.yahoo.co.jp/">Yahoo!</a>
</p>

<p>
    <input id="sample_button4" type="button" value="WebViewでYahoo!を開く">
</p>

</body>
</html>

スタイルシートは通常のWEB制作と同様に作ればよいので、ここでは割愛します。
sample2.htmlも何でもよいので割愛します。

次にsample.jsを作成します。
読み込み時、各ボタンにクリックイベントを設定します。

window.onload = function()
{
    // ボタン1
    document.getElementById("sample_button1").setAttribute("onclick", "myapi.showToast('トースト', 'SHORT');");

    // ボタン2
    document.getElementById("sample_button2").setAttribute("onclick", "myapi.showAlert(document.getElementById('msg').value);");

    // ボタン3
    document.getElementById("sample_button3").setAttribute("onclick", "myapi.openweb('http://www.yahoo.co.jp/');");

    // ボタン4
    document.getElementById("sample_button4").setAttribute("onclick", "myapi.openweb2('http://www.yahoo.co.jp/');");
};

ここまでの状態ですと、画面が回転したときにページが初期化されてしまいます。
それを避けるために、マニフェストのActivityタグに以下の属性を追加します。

android:configChanges="orientation|keyboardHidden"

インターネットを介してWEBページを表示するのでパーミッションの追加も忘れずに。
AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />

ここまでで一通りは完成ですが、WebViewでYahoo!を表示し、更にリンクをクリックした際、
ブラウザアプリでページが開いてしまいます。

それを回避し、同じWebViewでページを開いていくようにするには
ActivityのonCreateに以下を追加します。

// リンクをクリックした時に同WebViewで表示するように
web.setWebViewClient(new WebViewClient(){
@Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return false;
    }
});

または

web.setWebViewClient(new MyBrowserClient());

とし、アクティビティクラス内にプライベートクラスを記述します。

private class MyBrowserClient extends WebViewClient {
    public boolean shouldOverrideUrlLoading(WebView web, String url) {
        web.loadUrl(url);
        return true;
    }
}

端末のバックキーについて

通常、端末のバックキーを押すとアプリが終了しホーム画面等へ戻ってしまいます。
ブラウザアプリでは履歴を辿って前の画面に戻ってくれますので、
それと同様の処理をするようにします。
アクティビティクラスに以下を追加します。

public boolean onKeyDown(int keyCode, KeyEvent event) {
    // BACKキーで戻る
    if(keyCode == KeyEvent.KEYCODE_BACK && web.canGoBack()) {
        web.goBack();
        return true;
    }
    return super.onKeyDown(keyCode,  event);
}

他にも端末内の画像を表示したりすることもできます。
JavaScript APIクラスに以下を追加

class JavaScriptObject {

    ...省略

    String PATH = Environment.getExternalStorageDirectory().getPath();

    ...省略

    public String getPATH() {
        return PATH;
    }

}

HTMLファイルに以下を追加

<p>
    <img id="image">
</p>

JavaScriptでパスを取得して画像を表示

document.getElementById("image").src = myapi.getPATH() + "/DCIM/sample.png";

ただし、普通に画像を表示すると見た目上若干ぼやけた感じに見えてしまいます。
これを回避するには、2倍のサイズで画像を作成し、半分のサイズで表示するようにしましょう。

ちなみに私はこれでヘルプページ等を表示したりしています。
更新し易くて便利です。

この記事がお役に立ちましたらシェアお願いします
7,381 views

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です