このサイトでは、分析、カスタマイズされたコンテンツ、および広告に Cookie を使用します。このサイトを引き続き閲覧すると、Cookie の使用に同意するものと見なされます。
Hi, Developers,
straightapps.com
最終更新日 July 11, 2018
トップページ > Android 開発トップ > JNI でウェブサイトを開く

Android 開発

ここでは、JNI でウェブサイトを開く方法を記載しています。

Android ネイティブアプリでは、画面にテキストを表示するのが非常に難しいようです。

すべてを画像で用意すると apk のサイズが大きくなり、Google によれば、apk サイズが大きくなるほどダウンロードされなくなるそうです。
簡単なヘルプのみ apk に置いて、詳細な情報をウェブに置こうと考えたとき、 ネイティブアプリで WebView コントロールが使用できないようであることがわかりました。
そこで、JNI で URL(URI)を開くコードを実行して、標準のブラウザで(あるいは1つを選択してもらって) ウェブサイトを開く方法を実装できましたので、記述します。

ご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。

JNI でウェブサイトを開く(JNI の準備)

投稿 January 25, 2018, 更新 July 11, 2018(様式変更)

アプリには、簡単な、あるいは詳細な操作方法などを記載した、ヘルプ画面が必要です。
ところが Android ネイティブアプリでは、画面にテキストを表示するのが 非常に難しい ( とりあえず ASCII のみ出力できるようにしましたので、記事で追加予定です。 ) ようです。 WebView コントロールが使用できればそれでいいのですが、ネイティブアプリでは無理みたいです。 少なくとも Windows のコントロールのようには使用できないようです。

本来、Android アプリとしては、開発のベースを Java にして、必要な部分だけネイティブコードを呼び出して高速化する、 というのが一般的な手法のようですが、 何でも自由にやりたい思想のもと、完全ネイティブアプリを選んでしまったので、苦労は仕方ありません。

apk サイズを小さく保つために、最小限の情報のみ apk に置いて、詳細情報はウェブサイトに置くと決め、 ブラウザでウェブサイトを開くことにしました。
そのため、JNI で URL(URI)を開くコードを実行して、標準のブラウザで(あるいは1つを選択してもらって) ウェブサイトを開く方法を実装できましたので、記述します。

JNI ( Java と他の言語をつなぐ Java Native Interface の略です ) を利用しますので、Java Virtual Machine を準備しておく必要があります。

JVM ( Java Virtual Machine ) の準備はいつでも同じです。
コードは、JNI によるパブリックなパスの取得に記載していますので、必要でしたら、参照してください。

▲ページ先頭へ

JNI でウェブサイトを開く

投稿 January 25, 2018, 更新 July 11, 2018(様式変更)

ブラウザでウェブサイトを開く、という動作を Java で実行する場合は、次のようにするようです。

Uri uri = Uri.parse("https://www.straightapps.com/");
Intent i = new Intent(Intent.ACTION_VIEW, uri);
startActivity(i);

Android Developers では、 Uri(android.net.Uri)の parse 関数に String を渡すと、指定の URI 文字列をエンコードして Uri クラスを作成して返す、とされています。

そして、その Uri を開く動作を持った Intent(android.content.Intent)を作成して、 startActivity 関数で、実行する、という流れです。

jclass intentClass = env->FindClass("android/content/Intent");

で、Intent クラスを取得できます。jclass は数値で、例えば 0x200001 といった値が返されれば、成功しています。 0 が返された場合は失敗、FindClass 関数に不正な文字列を渡すと、処理が戻らなくなるようです。

取得した Intent クラスは定義であり、インスタンスではないため、コンストラクタを実行して実体化が必要です。 まずは、コンストラクタを取得しておきます。

Intent( String action, Uri uri );
jmethodID intentConstMethod = env->GetMethodID(intentClass, "", "(Ljava/lang/String;Landroid/net/Uri;)V");

同様に、Uri クラスを取得して、parse メソッドへのポインタを取得します。

jclass uriClass = env->FindClass("android/net/Uri");
jmethodID parseMethod = env->GetStaticMethodID(uriClass, "parse", "(Ljava/lang/String;)Landroid/net/Uri;");

Intent を初期化するには、ACTION_VIEW 定数を取得する必要があります。
Android Developers では、
Constant Value: "android.intent.action.VIEW"
と記載されていますので、

jstring actionString = env->NewStringUTF("android.intent.action.VIEW");

で、問題なく動作していますが、DIRECTORY_DOWNLOAD のように取得すべきなのかもしれません。 詳細は、「JNI によるスタティックな定数の取得」に記載してあります。

開きたい URL 文字列を Uri.parse 関数に渡して、Uri を得ます。
文字列(const char*)を NewStringUTF 関数に渡して jstring に変換しておきます。
String strj = new String("abc");
は、
jstring strj = env->NewStringUTF("abc");
のように置き換えられますので、parse 関数呼び出しまでは、次のように書けます。

jstring urlString = env->NewStringUTF(uriText);		// uriTextは const char*文字列
jobject uri = env->CallStaticObjectMethod(uriClass, parseMethod, urlString);

Java クラスはすべて、jobject と表現されますので、uri は Uri クラスですが jobject です。
続けて、new で Intent クラスを生成していますので、先に用意したコンストラクタ等を利用します。

jobject intentObject = env->NewObject(intentClass, intentConstMethod, actionString, uri);

intentClass は、android.content.Intent を FindClassした jclass です。
intentConstMethod は、Intent のコンストラクタです。
actionString は、"android.intent.action.VIEW" を jstring にしたものです。
そして uri は、URL をエンコードしたものです。
これらを使って、NewObject 関数で実体化しています。

最後に、startActivity 関数で、Intent を発行します。

jclass activityClass = env->GetObjectClass(app->activity->clazz);
jmethodID startActivity = env->GetMethodID(activityClass, "startActivity", "(Landroid/content/Intent;)V");
env->CallVoidMethod(app->activity->clazz, startActivity, intentObject);

app は struct android_app* です。
app->activity->clazz は、命名ミスであり、"activity"を意味しているようです。 ですので、これは、NativeActivity のインスタンスを指している、ということになります。
CallVoidMethod 関数は、戻り値がない関数の呼び出しを行う関数です。

私は関数にまとめましたので、
bool runBrowser(struct android_app* app, const char* uriText);
のようにすると便利かと思います。
このサイトの記事がじゅうぶん増えて軌道にのった暁には、関数ごとまとめて提示したいと考えてはおりますが・・・。

▲ページ先頭へ

どうやって使うか?

投稿 January 25, 2018, 更新 July 11, 2018(様式変更)

トピックには直接関係ありませんが、runBrowser 関数ができたら、どう使うか、 (今後の自身のトピック指針のために)書いておきます。

タッチ入力の取得(基本編)のように、 engine_handle_input 関数が呼び出されたときに、タッチ位置等がわかりますので、 自分で画面に描画したボタンの位置であることが検出されたら、この関数を呼び出す、ということになります。
Android 端末にはさまざまな画面サイズがあり、Windows のような座標指定は OpenGLES ではできませんので、 変換などの操作が必要になります。
また、画面の描画にはイメージを直接描けず、テクスチャにして貼り付ける必要がありますので、 このあたりは Windows(の従来のデスクトップアプリ)とはまったく異なります。
本機能のテストだけなら、「画面のどこかがタッチされたら」の実装は簡単にできますが。

▲ページ先頭へ

関連トピックス

JNI によるパブリックなパスの取得
JNI による、Download 等のパブリックなパスの取得方法を記載しています。


その他のおすすめ

おすすめ記事はありません。

JavaScriptが無効です
▲ページ先頭へ


© 2017-2019 StraightApps.com 無断転載を禁じます。No reproduction without permission.