ニュースなどの情報系アプリやデータが必要な AI系アプリを作ろうと思った時、Androidアプリに Web機能が必要に。
今回は公式ドキュメント: Android Developers を元に以下の操作を行えるようにテストしてみました。
単にアプリ内でWebページを表示
リンクをタップしてもアプリ内で移動
JavaScriptの有効化
戻るボタンの有効化
Webページを表示するアプリに広告を付けてみた
Androidアプリに Web機能を考えている方、ご参照下さい。
【はじめてのAndroidアプリ開発】アプリ内でWebページを表示・操作する方法 アプリ内でWebページを表示
アプリ内でWebページを表示させようと思うと、WebView
クラスが便利。公式ドキュメント に従って作業してみました。
<uses-permission android:name="android.permission.INTERNET" />
まずはアプリでインターネット通信を行うための設定。 AndroidManifest にパーミッションを追加します(上図参照)。
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
次はレイアウト。 WebView
クラスを扱えるように、 activity_main.xml 内に <WebView ....
を設置(上図参照)。
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("https://blog.codecamp.jp");
そして最後は MainActivity.java でビューの設定と URL の指定(上図参照)。上記コードを MainActivity.java に貼り付けると、青色のポップアップが表示されると思います。これは必要なクラスをインポートしますか?という確認。今回の場合は WebView
クラス必要になってきますので、アドバイス通り Ctrl+Enter でクラスをインポートしましょう。 Ctrl+Enter キーを押すと、自動的に import android.webkit.WebView;
が MainActivity.java に追記されます。
これでアプリ内で Webページを表示するための設定は完了です。エミュレーターを起動して、様子を確認してみましょう。
アプリ内でWebページを表示した結果
エミュレーターを起動すると、一見上手く Webページが表示されているように思いますが、
リンクをタプしてみると、アプリを出て、Chromeブラウザでリンク先を開こうとします(上図真ん中)
一部画像や埋め込みコード(iframe)が無効に(上図右)
戻るボタンを押すと、アプリが終了
どうもいつも使うブラウザとは様子が違ってくるみたいですね。 WebView の用途は人それぞれと思いますが、ブラウザと同じように動くよう上記 3つの項目をクリアしてみました。
一番最初の状態のコード
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.oshimamasara.webviewmaster000">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
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>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.oshimamasara.webviewmaster000;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
WebViewのみのコード (アプリ内リンク移動❌、JavaScript❌、戻るボタン❌)
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.oshimamasara.webviewmaster000">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
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>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.oshimamasara.webviewmaster000;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("https://blog.codecamp.jp");
}
}
リンクタップでもアプリ内の表示に(同一ドメインのみ表示)
現在の状態では、リンクをタップした時、ブラウザが起動し、リンク先を開こうとします。しかし、情報系アプリを考えた時、リンクタップで自分のアプリから出ていかれると、広告収益の機会を失います。できればアプリ内でリンク先も開いてもらいたいもの。
公式ドキュメントには「同一ドメインに限ってリンクをアプリ内で開く」方法が紹介されていました。
★追加コード MainActivity.java★
その一
myWebView.setWebViewClient(new MyWebViewClient());
そのニ
//アプリ内でWebページオープン 特定ドメイン以外はブラウザ起動
// text https://developer.android.com/guide/webapps/webview#HandlingNavigation
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if ("blog.codecamp.jp".equals(Uri.parse(url).getHost())) {
// This is my website, so do not override; let my WebView load the page
return false;
}
// Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
上図の様にこのコードを MainActivity.java に貼り付けると、またクラスのインポートを促すポップアップが表示されますので、 Alt+Enterキーでインポートしましょう。そしてエミュレーターを起動すると、今度はリンクをタップしてもアプリ内でページを開くことができました。しかしそれは同一ドメインに限った話。外部リンクをタップすると、ブラウザから外部リンクを開こうとします。
追加したコードについては、まず ”そのニ” の部分で クラス: WebViewClient を継承する MyWebViewClient というクラスを新規作成。そしてその MyWebViewClient では、リンク先の「ドメイン」によって処理を振り分け。今表示しているサイトと同じドメイン(今回の場合: blog.codecamp.jp)であれば、今の WebView を使ってリンク先を OPEN。しかし、リンク先が今表示しているサイトと違うドメインだったらブラウザで起動、という内容になっています。
そして新しいクラス MyWebViewClient の実行は、その一の myWebView.setWebViewClient(new MyWebViewClient());
部分。新しいクラス MyWebViewClientをインスタンス化し、実行しています。
基本的に他人のサイトも自分のアプリ内で表示していると”著作権”の問題が絡んできますので、使用用途を踏まえた上でリンク先の開封を制御しましょう。
とはいうものの、外部サイトもアプリ内で表示させたい時、あるかもしれません。
サイト内リンクのみアプリ内でWeb閲覧可にしたMainActivity.java (アプリ内同一サイトのみリンク移動○、JavaScript❌、戻るボタン❌)
MainActivity.java
package com.oshimamasara.webviewmaster000;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("https://blog.codecamp.jp");
myWebView.setWebViewClient(new MyWebViewClient());
}
//アプリ内でブラウザオープン 特定ドメイン以外はブラウザ起動
// text https://developer.android.com/guide/webapps/webview#HandlingNavigation
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if ("blog.codecamp.jp".equals(Uri.parse(url).getHost())) {
// This is my website, so do not override; let my WebView load the page
return false;
}
// Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
}
外部リンクもアプリ内で表示
外部リンクをアプリ内で開く際は、著作権の問題が発生します。用途をご確認の上、適切にご利用下さい。
//アプリ内でWebページオープン 外部リンクもアプリ内でOPEN
// text https://developer.android.com/guide/webapps/webview#HandlingNavigation
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//if ("blog.codecamp.jp".equals(Uri.parse(url).getHost())) {
// This is my website, so do not override; let my WebView load the page
return false;
}
// Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
//Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
//startActivity(intent);
//return true;
//}
}
外部リンクもアプリ内で開きたい場合は、上記のように if文のところを編集すれば OK。 現在の WebView を使って外部リンクも開いてくれます。外部リンク毎にブラウザを起動しないので、ページ移動がスムーズ。
サイト内リンク・サイト外リンク、アプリ内でWeb閲覧可にしたMainActivity.java (アプリ内でリンク移動○、JavaScript❌、戻るボタン❌)
MainActivity.java
package com.oshimamasara.webviewmaster000;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("https://blog.codecamp.jp");
myWebView.setWebViewClient(new MyWebViewClient());
}
//アプリ内でブラウザオープン 特定ドメイン以外はブラウザ起動
// text https://developer.android.com/guide/webapps/webview#HandlingNavigation
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//if ("blog.codecamp.jp".equals(Uri.parse(url).getHost())) {
return false;
}
//Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
//startActivity(intent);
//return true;
//}
}
}
JavaScriptの設定
WebView
クラスを使って Webページを読み込んだ場合、 JavaScriptは無効になっています。恐らくセキュリティ面と思いますが、おかげで Webページの読み込みが早いというメリットもありますね。しかし、 JavaScriptが無効では、
画像が上手く表示されない
YouTube の埋め込み動画も❌
といった感じで、見難いです。世の中の Webページの 90% 以上は JavaScript を利用していると言われていますので* 、JavaScriptも意図的に操作できると便利そう。
WebView 内での JavaScript の有効・無効は以下のコードで制御。
myWebView.getSettings().setJavaScriptEnabled(true);
setJavaScriptEnabled()
が True だったら JavaScript が有効で、 False だったら無効。この JavaScript の設定コードについては、 ビューを設定している
myWebView = (WebView) findViewById(R.id.webview);
より後に記述する必要があります。またこのビューの設定コードも先ほどまでと違っていることに気づきますでしょうか? myWebView
の設定を上の段で行っています。
JavaScriptを有効にしたMainActivity.java (アプリ内でリンク移動○、JavaScript○、戻るボタン❌)
MainActivity.java
package com.oshimamasara.webviewmaster000;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
WebView myWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myWebView = (WebView) findViewById(R.id.webview);
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.loadUrl("https://blog.codecamp.jp");
myWebView.setWebViewClient(new MyWebViewClient());
}
//アプリ内でブラウザオープン 特定ドメイン以外はブラウザ起動
// text https://developer.android.com/guide/webapps/webview#HandlingNavigation
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//if ("blog.codecamp.jp".equals(Uri.parse(url).getHost())) {
return false;
}
//Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
//startActivity(intent);
//return true;
//}
}
}
戻るボタンの有効化
//戻るボタン
@Override
public void onBackPressed() {
if(myWebView!= null && myWebView.canGoBack())
myWebView.goBack();// if there is previous page open it
else
super.onBackPressed();//if there is no previous page, close app
}
WebView
クラスを使って Webページを表示させた場合、普段使う画面下部のナビゲーションボタン”戻る”が使えません。”戻る”ボタンをタップすると、アプリが終了します。 WebView
使用時に”戻る”を使うには、明示的に”戻る”機能を記述する必要がありますね。
上記コードの様にまずは onBackPressed()
メソッドで”戻る”ボタンのタップを感知し、 ページが進んでいて、直克”戻る”機能が有効であれば goBack()
メソッドで戻る。前のページがなかったり、”戻る”機能がない場合は、アプリ終了、という内容に。
戻るボタンを有効にしたMainActivity.java (アプリ内でリンク移動○、JavaScript○、戻るボタン○)
MainActivity.java
package com.oshimamasara.webviewmaster000;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
WebView myWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myWebView = (WebView) findViewById(R.id.webview);
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.loadUrl("https://blog.codecamp.jp");
myWebView.setWebViewClient(new MyWebViewClient());
}
//アプリ内でブラウザオープン 特定ドメイン以外はブラウザ起動
// text https://developer.android.com/guide/webapps/webview#HandlingNavigation
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//if ("blog.codecamp.jp".equals(Uri.parse(url).getHost())) {
return false;
}
//Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
//startActivity(intent);
//return true;
//}
}
//戻るボタン
@Override
public void onBackPressed() {
if(myWebView!= null && myWebView.canGoBack())
myWebView.goBack();// if there is previous page open it
else
super.onBackPressed();//if there is no previous page, close app
}
}
広告を貼ってみました
せっかくなので今回の WebView
を使った Web表示にバナー広告を設定してみました。グノシーやLINEニュースのように多数のメディアサイトやニュースサイトをアプリ内で扱うようにすれば、収益化も夢じゃないように思えてきますね。
上図のコード/ GitHub
補足情報
WebView
クラスを使ってアプリ内で Webページを表示するわけですが、その時端末側ではブラウザの Chromium が呼び出されています。その他にも Logcat の中にはたくさんの情報が詰まっていますので、一読してみるとおもしろいでしょう。
アプリ内でWebページを表示するアプリ開発の様子(動画)
VIDEO
本テキスト合わせてご参照下さい。
コード/ GitHub
今回はアプリ内で、単一の Webページを開いたり、リンク先に移動したり、戻ったり、 JavaScript を制御する方法をご紹介させて頂きました。これが”単一”ではなく複数サイトを横断的に移動できるようになると、もしくは更新のあったサイトだけマーキングされアプリ内で閲覧できるようになると、便利なアプリになりそう。
自分だけのニュースアプリだって作れそうでうすね
またアプリ内で Web ページを開くことで「翻訳機能」「音声読み上げ機能」などお好みの機能を加えることだって可能。
そして記事内のキーワードを収集し、 AI でその記事がネガティブかポジティブか、など判定することだってできるでしょう。
このようにアプリ内で Webページを表示したり、データ収集できると色々なことに応用できそうです。そして最後に”広告”か”課金機能"を加えれば、”収益化”も狙えますね。
さてそんな夢のある Androidアプリ開発ですが、参考書だけ・・ ではちょっとシンドイ...でしょうか。せっかくのモチベーションも勉強方法次第では、即ゼロになりかねません。
「ちょっとこれは無理だな」「アプリ開発、難しい...」と思った時、一度学習方法を見直してみませんか? 忙しくても、どこにいてもオンラインのプログラミング・スクールが支えになってくれるかもしれません?
現在 CodeCamp では、 「オンライン」「プログラミング」 はじめての方向けに無料体験を実施しています。アプリ開発やプログラミング、諦める前に一度「無料体験」やってみませんか?
詳しくは 公式ページ よりチェックしてみて下さい。