Bubblewrapを使ってWebサイトをネイティブAndroidアプリに変換する方法 – ステップバイステップ完全ガイド
アプリ開発の経験がないWeb開発者の方(私もその一人でした!)にこそ読んでほしい記事です。新しいフレームワークや言語を覚えることなく、自分のWebサイトをネイティブアプリへと変える方法を解説します。具体的には、WebサイトをPWA(プログレッシブウェブアプリ)に変換し、Google Playで公開できるところまでを学べます。
流れとしては、まずWebサイトをPWA化し、次にGoogleが提供する無料のコマンドラインツールBubblewrapを使って、そのPWAをAndroidアプリとしてパッケージ化します。それでは始めましょう。
前提条件
このチュートリアルを進めるにあたり、以下が必要です。
Web開発の基礎知識
インターネット上に公開されているサイトであること、およびソースコードへアクセスできること
必要なツールのインストールにnpmを使用するため、Node.jsがインストールされていること
注意: 本チュートリアルはViteプロジェクトをベースにしていますが、Bubblewrapを使う最終的な手順自体は、どのWebフレームワークでも同じです。
目次
PWAとは?
Bubblewrapとは?
- TWA(Trusted Web Activity)とは?
- TWAが信頼性を検証する仕組み
ステップ1 – ViteでPWAを構成する
- アプリのアイコンを作成する
- Vite PWAプラグインをインストールする
- プラグインを設定する
ステップ2 – Androidアプリを作成する
- ビルド用フォルダを作成する
- Bubblewrap CLIをインストールする
- プロジェクトを初期化する
- initコマンドのトラブルシューティング
ステップ3 – Bubblewrapの質問に答える
ステップ4 – アプリをビルドする
ステップ5 – TWA検証を設定する
- .well-knownフォルダとは?
- delegate_permission/common.handle_all_urlsとは?
ステップ6(任意) – アプリ内の体験をカスタマイズする
まとめ
PWAとは?
PWAはProgressive Web Application(プログレッシブウェブアプリ)の略で、Webサイトをネイティブアプリと同等の見た目・操作性にすることを目指した技術です。ブラウザでサイトを閲覧した際に、「インストール」アイコンが表示され、スマホやPCに追加できた経験があれば、それはすでにPWAを使ったことのあるということです。
しかし、PWAの魅力は見た目だけにとどまりません。オフラインでも動作する、プッシュ通知を送れるなど、まさにアプリらしい機能も備えています。
PWAは、次の2つの主要コンポーネントで成り立っています。
マニフェストファイル: アプリ名、アイコン、開始URLなど、アプリの基本情報を記述するファイルです。
サービスワーカー: プロキシのように振る舞うバックグラウンドのJavaScriptファイルです。キャッシュ制御やプッシュ通知は、メインスレッドとは別のスレッドで動作するこのサービスワーカーが担当します。
この2つが揃っていないと、ブラウザはユーザーに対してアプリのインストールを許可しません。
マニフェストファイルとサービスワーカーは、いわばブラウザにとっての「チェックリスト」です。サイトにアクセスすると、ブラウザはこの2つの存在を確認します。両方が正しく設定されていれば、ブラウザは「これは本物のPWAだ」と判断し、インストールアイコンを表示します。逆に、どちらかが欠けていれば、それは普通のWebサイトとして扱われ、インストール機能は使えません。
Bubblewrapとは?
Bubblewrapは、Googleが開発したコマンドラインツールで、PWAをTrusted Web Activity(TWA)という仕組みを使ってAndroidアプリに変換します。
TWAの作成プロセスは本来複雑ですが、Bubblewrapを使えば、PWAのマニフェストファイルをもとにAndroidアプリパッケージ(APK / AAB)を簡単に生成できます。
TWA(Trusted Web Activity)とは?
Trusted Web Activity(TWA)は、稼働中のWebサイトをAndroidアプリ内でフルスクリーン表示できる、比較的新しいAndroidの機能です。仕組みとしてはブラウザ上でサイトを動かしているのですが、アドレスバーが表示されないため、まるでネイティブアプリのような体験になります。
ただし、このフルスクリーン表示を有効にするには、アプリが「信頼された(trusted)」ものである必要があります。
ここで登場するのが、いわば「秘密の合言葉(シークレットハンドシェイク)」です。Androidは、アプリの開発者とWebサイトの所有者が同一人物であることを確認しなければなりません。所有権の証明がない場合、TWAはフォールバックモードで動作し、画面上部にアドレスバーが表示されてしまうため、ネイティブアプリらしい印象が台無しになってしまいます。
TWAが信頼性を検証する仕組み
この信頼関係は、Digital Asset Linksというシステムによって検証されます。自分のWebサイト上に特別なファイルを設置し(実装編で詳しく説明します)、そこにアプリ固有のデジタルフィンガープリントを記載します。ユーザーがアプリを開くと、Android OSがこのファイルをチェックし、フィンガープリントが一致すれば、アプリに「信頼済み」のステータスが付与されます。するとアドレスバーが消え、ディープリンクなどの機能も有効になります。
この関係性は、Google公式のテストツール「Digital Asset Links Verifier」を使えば、自分でも確認できます。
それでは、仕組みが理解できたところで、実際に構築していきましょう。
ステップ1 – ViteでPWAを構成する
最初のステップは、PWAに必須の2つのコンポーネント、すなわちマニフェストファイルとサービスワーカーを追加することです。これにより、ブラウザがあなたのサイトを「インストール可能」と認識できるようになります。
このガイドはViteで構築されたプロジェクトを前提としていますが、専用プラグインのおかげで作業はとても簡単です。別のツールを使っている場合でも考え方は同じなので、それぞれの環境に応じた手順を調べて試してみてください。
アプリのアイコンを作成する
コードに手を加える前に、まずアプリのアイコンを用意しましょう。Androidでは、ランチャーアイコン(ホーム画面に表示されるもの)とスプラッシュスクリーン(アプリ起動時に表示される画面)に、特定のサイズが求められます。
必要なのは192x192ピクセルと512x512ピクセルの2種類です。「Favicon Generator」のようなツールを使えば、メインのロゴをアップロードするだけで、必要なサイズを一括生成できます。
生成されたファイルをダウンロードし、192x192と512x512の画像をプロジェクトのpublicフォルダに配置してください。

Vite PWAプラグインをインストールする
PWAにはマニフェストファイルとサービスワーカーが必要ですが、これらを手作業で作ることも、このプラグインを使えば自動化できます。プロジェクトをビルドするたびに、manifest.jsonとservice-worker.jsを自動生成してくれます。
npm install vite-plugin-pwa -D
プラグインを設定する
続いて、プラグインを使ってアプリのマニフェストを設定します。vite.config.tsファイルを編集しましょう。ここで、アプリの名前や使用するアイコンなどを指定します。
vite.config.tsの例:
export default defineConfig({
plugins: [
VitePWA({
registerType: "autoUpdate",
manifest: {
name: "your app name",
short_name: "your app short name",
description: "write any description",
theme_color: "#0d1117",
background_color: "#ffffff",
display: "standalone",
start_url: "/",
icons: [
{
src: "/web-app-manifest-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "/web-app-manifest-512x512.png",
sizes: "512x512",
type: "image/png",
},
],
},
}),
]
これで、npm run buildを実行すると、プラグインがマニフェストとサービスワーカーを自動生成してくれます。あとは変更内容をデプロイすれば、あなたのWebサイトは晴れてPWAになりました。
ステップ2 – Androidアプリを作成する
WebサイトのPWA化が完了したら、次はBubblewrapを使ってAndroidアプリとしてパッケージ化していきます。
ビルド用フォルダを作成する
まず、Androidプロジェクト関連のファイルを格納する専用フォルダを作ります。プロジェクトのルート直下に新しいフォルダを作成してください。ここではandroidという名前にします。
project/
├── client/
├── server/
└── android/
作成したら、そのフォルダに移動しておきます。
Bubblewrap CLIをインストールする
npm install -g @bubblewrap/cli
プロジェクトを初期化する
次に、initコマンドを実行します。Bubblewrapは公開中のWebサイトに接続し、Viteが生成したmanifest.webmanifestを読み取って、その情報をもとにAndroidプロジェクトの雛形を作成してくれます。
bubblewrap init --manifest=https://your-website-domain/manifest.webmanifest
your-website-domainの部分を実際のURLに置き換えて実行してください。
initコマンドのトラブルシューティング
initコマンドの実行中、BubblewrapはJava Development Kit(JDK)とAndroid SDKという2つの重要なソフトウェアを必要とします。自動インストールを提案してくれるので、案内に従いましょう。
JDKのセットアップ:
? Do you want Bubblewrap to install the JDK (recommended)?
(Enter "No" to use your own JDK 17 installation) (Y/n)
私の場合、BubblewrapにJDKのインストールを任せたところ、ファイルのダウンロードまでは成功したものの、「展開(decompressing)」の段階で失敗しました。同じ問題に遭遇しても慌てないでください。手動でインストールすれば解決します。
プロンプトにはNoと答えます。
Adoptiumなどの配布元から推奨バージョン(通常はJDK 17)をダウンロードします。
インストール後、システムの環境変数にJDKの
binフォルダのパスを追加します。環境変数の設定方法がわからない場合は、「Set Environment Variables」などの解説サイトを参考にしてください。Bubblewrapがパスを尋ねてきたら、
C:\java\jdk-17.0.16.8-hotspotのように直接入力します。
Android SDKのセットアップ:
JDKのセットアップが完了したら、次はAndroid SDKの設定です。
? Do you want Bubblewrap to install the Android SDK (recommended)?
(Enter "No" to use your own Android SDK installation) (Y/n)
私はAndroid SDKを持っていなかったため、Yesを選んでBubblewrapに任せましたが、特に問題は発生しませんでした。
もしAndroid SDKのセットアップで問題が起きた場合は、JDKと同様に手動でセットアップし、パスを直接指定すれば大丈夫です。
ステップ3 – Bubblewrapの質問に答える
SDKの準備が整うと、Bubblewrapからアプリの設定に関するいくつかの質問が表示されます。ここでの回答は、アプリの設計図となるtwa-manifest.jsonファイルの作成に使われます。
Domain: Enterキーを押す(マニフェストから自動入力される)
Application name: アプリの正式名称
Application ID: (例: chat.yourapp.twa)
Display mode: standalone
Orientation: portrait
Status bar color: Enterキーを押す(デフォルト値を採用)
Splash screen color: Enterキーを押す(デフォルト値を採用)
Icon URL: Enterキーを押す(デフォルト値を採用)
Include support for Play Billing?: Google Playのアプリ内課金を使うならY、そうでなければN
Request geolocation permission?: 位置情報へのアクセスが必要ならY、そうでなければN
この中で特に重要なのが、キーストア(keystore)とキーの設定です。
First and Last names: 氏名
Organizational Unit: Developer など任意の文字列
Organization: 組織名
Country (2-letter code): 国コード(2文字)
Password for key store: 新しいパスワードを入力
Password for key: 同じパスワードを再入力
注意: キーストアとキーのパスワードは必ず同じにしてください。異なるとエラーが発生します。詳細はこちらのIssueを参照してください: Bubblewrap Issue。
ステップ4 – アプリをビルドする
bubblewrap build --universalApk
このコマンドでアプリのビルドが始まります。universalApkフラグを付けると、.apkと.aabの両方が生成されます。Play Storeに公開する予定があるなら.aabファイルをアップロードすればOKですが、ローカルでのテストにはAPKファイルが必要です。このフラグを付けておけば両方のファイルが手に入るので便利です。フラグなしの場合は.aabのみが出力されます。
ステップ5 – TWA検証を設定する
ビルドが完了してAPKが手に入ったら、スマホに転送してテストしてみましょう。アプリを開くと、ブラウザのアドレスバーが表示されているはずです。これは、アプリとWebサイトの間の「信頼関係」をまだ設定していないためです。早速修正しましょう。
フロントエンドプロジェクトのpublicフォルダ内に、.well-knownという名前のフォルダを作成し、さらにその中にassetlinks.jsonというファイルを作ります。
frontend/
├── public/
├── .well-known/
└── assetlinks.json
.well-knownフォルダとは?
well-knownフォルダは、プロトコルの設定を定義するファイルを格納するための場所です。外部のシステムが、あなたのWebサイトの検証情報を見つけられるようにするために使われます。今回のケースでは、アプリ側がWebサイト上のwell-knownフォルダを参照し、検証を行うという流れになります。
以下の内容をassetlinks.jsonに貼り付けてください。
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "chat.yourapp.twa",
"sha256_cert_fingerprints": [
"your_sha256_fingerprint"
]
}
}
]
delegate_permission/common.handle_all_urlsとは?
これは、ドメインではなくアプリ側でリンクを開くための特別なフラグです。簡単に言えば、ディープリンクとして機能します。アプリをインストールした後、WhatsAppなどからあなたのWebサイトのリンクをクリックすると、ブラウザではなくアプリが開くようになるのです。
package_nameフィールドには、Androidのビルドフォルダ内にあるtwa-manifest.jsonで確認できるpackageIdを指定します。
続いて、フィンガープリントを取得しましょう。以下のコマンドを実行します。
keytool -list -v -keystore android.keystore -alias android
alias名には、プロジェクト作成時に自分で設定した値を入力してください。コマンドを実行するとキーストアのパスワードを聞かれるので入力すると、SHA256フィンガープリントが表示されます。それをコピーして、assetlinks.jsonのsha256_cert_fingerprints配列内に貼り付けてください。あとはこの変更を本番環境に反映させます。Digital Asset Linksで検証結果を確認できます。
以上で完了です!アプリをインストールして、動作を確かめてみてください。
ステップ6(任意) – アプリ内の体験をカスタマイズする
さらに一歩進んで、「Webサイトで表示するコンテンツ」と「モバイルアプリで表示するコンテンツ」を切り替えたいケースもあるでしょう。これは可能です!
Androidのビルドフォルダ内にあるtwa-manifest.jsonには、startUrlというフィールドがあります。存在しない場合は追加し、値を"startUrl": "/?twa=true"としてください。startUrlはアプリのエントリーポイントであり、ここではtwa=trueというクエリパラメータを付けています。
その後、bubblewrap build --universalApkで再度ビルドを実行します。
これで、アプリを開いたときのエントリURLがyourwebsitedomain.com/?twa=trueになります。
フロントエンド側では、たとえば次のように書けます。
const twaParam = queryParams.get("twa");
const [isTwa, setIsTwa] = useState<boolean>(() => {
return localStorage.getItem("isTwa") === "true";
});
useEffect(() => {
if (twaParam === "true") {
localStorage.setItem("isTwa", "true"); // 値をローカルストレージに保存
setIsTwa(true);
}
}, [twaParam]);
{isTwa? (
<Link to="/contact" className="underline hover:text-primary">
Contact
</Link>
) : (
<Link to="/download" className="underline hover:text-primary">
Download App
</Link>
)}
上記のコードでは、URLにtwa=trueというクエリパラメータが含まれているかどうかをチェックしています。存在する場合は、その情報をローカルストレージに保存し、ユーザー向けのコンテンツを出し分けています。
これで、アプリの完成です。
アプリ名やカラー、スプラッシュスクリーンなどを変更したい場合は、twa-manifest.jsonを編集して再度ビルドを実行するだけでOKです。
まとめ
BubblewrapはAndroid専用のツールです。クロスプラットフォーム対応のアプリを作りたい場合は、Capacitorなど別の選択肢があります。こちらについては、また別の記事で紹介する予定です。
ちなみに、私がBubblewrapで実際に作ったアプリはこちらで公開しています:「Stranger Talk」。ぜひチェックしてみてください。
記事に誤りを見つけた方や質問がある方は、LinkedInまたはInstagramまでご連絡ください。
最後までお読みいただきありがとうございました!
-
【ルート化不要】Fire ToolboxでAmazon Fireタブレットをカスタマイズする方法
Amazon Fireタブレットの見た目や動作に不満を感じていませんか?ロック画面に表示される広告、プリインストールされたAmazonアプリの強制、Googleアシスタントが使えないこと——そんな悩みを抱えている方は多いはずです。 実は、Fire OSはAndroidをベースに開発されているため、OSにはある程度の自由度があります。この柔軟性を最大限に活かすためのツールが「Fire Toolbox(FTB)」です。 Fire Toolboxでできるカスタマイズ Fire Toolboxを導入すれば、Amazon Fireタブレットを大幅に改善できます。主な機能は以下のとおりです。 Googl
-
スマホのWi-Fiが遅い原因はこれかも?「開発者向けオプション」でWi-Fiスキャン制限を解除する方法
スマホの画面ではWi-Fiの電波強度が満タン表示なのに、動画はバッファリングばかり、ページの読み込みは途中で止まり、ダウンロードはのろのろと進む——そんな経験はありませんか?プロバイダを疑ったり、ルーターを再起動したり、つい「宇宙のせい」にしたくなることもあるでしょう。しかし、本当の犯人はもっと身近なところ、あなたのスマホの設定の中に潜んでいるかもしれません。Androidには「Wi-Fiスキャン制限(Wi-Fi Scan Throttling)」という機能が標準で搭載されています。一見すると便利な機能ですが、実際には接続の応答性を下げる「見えないブレーキ」として働くことが少なくありません。幸