.NET MAUIのWebViewでExcelファイルを表示したいのに、iPhoneでは見えるのにAndroidだけ真っ白…というケースは珍しくありません。原因は「WebViewがOffice文書を直接描画できない」こと。この記事では、最小実装で確実に表示させる方法と、表示できない場合の切り分けまでまとめます。
Androidだけ真っ白になるときにまず押さえるポイント
結論から言うと、AndroidのWebViewはExcel(.xlsx/.xls)をブラウザのように“そのまま”レンダリングする機能を持っていません。そのため、ExcelのURLをWebViewに直接読み込ませても、表示が真っ白になったり、ダウンロード扱いになったりします。
一方でiOS(WKWebView)側は、配信方法や端末環境によってはOS側のプレビュー機能に寄った挙動になり、結果として「WebView内で見えているように見える」ことがあります。ここが「iPhoneでは表示できるのにAndroidではダメ」という体験差になりやすいポイントです。
| 観点 | iOS(WKWebView) | Android(WebView) |
|---|---|---|
| Office文書の扱い | 状況によってはプレビュー表示になり、見えているように感じることがある | Office文書をネイティブに描画しないため、基本的にそのままでは表示できない |
| 「WebView内で表示」の実態 | OS/ブラウザ側のビューアに依存することが多い | オンラインビューアや変換済みコンテンツが必要になりやすい |
| 安定させるコツ | iOSも同じ方式(オンラインビューア等)に寄せると差が減る | オンラインビューア埋め込み、PDF化、専用SDKなどで設計する |
方針は3つ:目的に合わせて選ぶ
「WebView内でそのままExcelを見たい」という要件を満たす現実的なルートは、主に次の3パターンです。
- オンラインビューアに渡してWebViewに埋め込む(最小工数・最も現実的)
- サーバー側でPDF/HTMLに変換してから表示する(表示の安定性を上げられる)
- アプリ内でExcelを解析して描画する(オフライン可能だが開発・容量コストが重い)
| アプローチ | オフライン | 表示の忠実度 | 実装コスト | 向いているケース |
|---|---|---|---|---|
| オンラインビューア(Google/Microsoft) | 不可 | 高い(サービス依存) | 低い | まず表示できることを優先、短納期、既存URLをそのまま使いたい |
| PDF/HTMLに変換して表示 | 条件付き(変換物を保持すれば可) | 中〜高(変換ロジック次第) | 中 | 表示の安定性と運用を重視、閲覧専用、外部サービス依存を減らしたい |
| アプリ内で解析して描画 | 可 | 実装次第(作り込むほど高い) | 高い | 完全オフライン必須、機密文書で外部にURLを渡せない、特殊要件 |
オンラインビューア埋め込みが最小コストで現実的な理由
「できればWebView内でそのままExcelを見たい」という要望に対し、オンラインビューアは次の意味で“現実解”です。
- アプリにExcelレンダラーを持たせない:実装・保守・アプリ容量の増加を回避できます。
- URLだけで成立:Azure Blob Storageなど「ファイルURLを発行できる」環境と相性が良いです。
- Androidでも表示の土台ができる:WebViewが理解できるHTMLに変換された状態で表示されます。
採用された解決策:Google Docs ViewerでExcelをWebView表示する
最も手軽で、Androidでも「WebView内にExcelが出る」状態を作りやすいのがGoogle Docs Viewerを経由する方法です。実際の描画はGoogle側が行い、アプリはWebViewでその結果ページを表示します。
仕組み
WebViewに直接ExcelのURLを渡すのではなく、次の形式のURLに変換して読み込みます。
これにより、Excel/WordなどのOffice文書でも、GoogleのオンラインビューアがHTMLとしてレンダリングしてくれるため、Android WebViewでも表示が成立しやすくなります。
実装手順
- ExcelファイルURLからクエリ文字列(SASトークンなど)を除いた“パス部分”だけを取り出す
- 拡張子(.xlsx/.xls/.doc/.docxなど)を判定する
- Excel/WordだけGoogle Docs ViewerのURLに変換してWebViewへ渡す
- それ以外(PDFや画像など)は元のURLをそのままWebViewへ渡す
C#(.NET MAUI)サンプル:URLから拡張子を判定してViewerに振り分ける
using System;
using System.IO;
public static class DocumentViewerUrl
{
public static string ToWebViewSource(string originalUrl)
{
if (string.IsNullOrWhiteSpace(originalUrl))
return originalUrl;
var extension = GetExtensionWithoutQuery(originalUrl);
// Excel / Word だけ Google Docs Viewer に流す(必要に応じて増やす)
if (extension is ".xlsx" or ".xls" or ".doc" or ".docx")
{
var encoded = Uri.EscapeDataString(originalUrl);
return $"https://docs.google.com/viewer?url={encoded}&embedded=true";
}
return originalUrl;
}
private static string GetExtensionWithoutQuery(string url)
{
// クエリ文字列を外したパスで拡張子判定(SASトークン付きでもOK)
// 例: https://example.blob.core.windows.net/container/a.xlsx?sv=...
// → a.xlsx の拡張子を取得する
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
{
// Uriにできない場合の保険("?" 以降を落とす)
var noQuery = url.Split('?')[0];
return Path.GetExtension(noQuery).ToLowerInvariant();
}
var path = uri.GetLeftPart(UriPartial.Path);
return Path.GetExtension(path).ToLowerInvariant();
}
}
実際の画面では、WebViewに上記で作ったURLを設定するだけです。
// 例:ページやViewModel側で
var fileUrl = "https://.../sample.xlsx?sv=..."; // SASトークンなど含んでOK
MyWebView.Source = DocumentViewerUrl.ToWebViewSource(fileUrl);
Google Docs Viewerのメリット
- URL変換だけで導入でき、実装負荷が低い
- Excel/Wordのプレビューに慣れているユーザーが多く、操作の学習コストが小さい
- WebView側で特殊設定が少なくても動きやすい
注意点(運用・制約)
- インターネット接続は必須です。オフラインでは表示できません。
- 外部サービス(Google)に依存します。URLをGoogleが取得できないと表示できません。
- ファイルURLが社内ネットワーク限定、IP制限、Cookie必須、認証必須などの場合、Google側が取得できず失敗します。
- Azure Blob Storageの「ストレージファイアウォール」や「プライベートエンドポイント」で外部アクセスを遮断している場合も同様に失敗します。
- 機密文書では、URL(SASトークン含む)を外部に渡すこと自体がポリシー違反になる可能性があります。
| よくあるつまずき | 原因 | 対処の方向性 |
|---|---|---|
| Viewerが真っ白/読み込みが終わらない | ファイルURLが外部から取得できない(認証・IP制限・期限切れ) | 公開可能なURLにする、SASの期限を伸ばす、アクセス制御を見直す |
| Excelは出るが一部シートが崩れる | ビューア側の変換限界(複雑な数式、グラフ、外部参照など) | PDF化を検討、閲覧要件(忠実度)を明確化 |
| SASトークン付きURLで失敗する | URLエンコード不足/二重エンコード | src/urlパラメータは一度だけ正しくエンコードする |
| ダウンロード扱いになってしまう | サーバー側のContent-Dispositionがattachment、またはMIMEが不適切 | inline配信の検討、ビューア経由に統一する |
GoogleとMicrosoft、どちらのオンラインビューアを選ぶべきか
両者は「URLを渡してプレビューを表示する」点では似ていますが、運用方針で向き不向きが出ます。迷ったら、まずは手元のファイルURLで両方試し、表示成功率が高い方を基準にすると失敗が少ないです。
| 比較ポイント | Google Docs Viewer | Microsoft Office Online Viewer |
|---|---|---|
| 導入の手軽さ | 高い(URL変換中心) | 中(JavaScript有効化など環境差の調整が必要なことがある) |
| レイアウトの再現性 | 文書による | 高いことが多い(Microsoft側のレンダリング) |
| 読み込み速度 | 比較的軽いことが多い | 重いことがあり、ローディングUIが重要 |
| 依存先 | Microsoft |
別解:Microsoft Office Online Viewer+Android WebViewの設定
Google依存を避けたい、またはMicrosoftのレンダリング品質を優先したい場合は、Microsoft Office Online Viewerを使う手もあります。こちらも基本は「ExcelをOffice Onlineに読み込ませ、そのプレビュー画面をWebViewで表示する」方式です。
Office Online ViewerのURL形式
WebViewに読み込ませるURLは次の形です。
srcにはファイルURLをURLエンコードして入れるのが安全です。
public static string ToOfficeOnlineViewer(string originalUrl)
{
var encoded = Uri.EscapeDataString(originalUrl);
return $"https://view.officeapps.live.com/op/view.aspx?src={encoded}";
}
Android WebView側の設定(MAUIのWebViewHandlerで有効化)
Office Onlineの表示にはJavaScriptが必要になることが多いため、Android側でWebView設定を追加します。MAUIではWebViewHandlerのマッピングに追記して、プラットフォーム設定を上書きするのが定番です。
using Microsoft.Maui.Handlers;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>();
builder.ConfigureMauiHandlers(handlers =>
{
WebViewHandler.Mapper.AppendToMapping("OfficePreview", (handler, view) =>
{
#if ANDROID
var settings = handler.PlatformView.Settings;
// Office Onlineの表示に必要になりやすい
settings.JavaScriptEnabled = true;
settings.DomStorageEnabled = true;
// ローカルファイル絡みの挙動を触る場合のみ有効化(必要性とリスクを理解した上で)
settings.AllowFileAccess = true;
settings.AllowFileAccessFromFileURLs = true;
settings.AllowUniversalAccessFromFileURLs = true;
#endif
});
});
return builder.Build();
}
}
あとは、WebViewのSourceにOffice OnlineのURLを設定します。
MyWebView.Source = ToOfficeOnlineViewer(fileUrl);
読み込みが遅い前提でUIを作る
Office Onlineのプレビューは処理が重く、環境によっては数秒〜十数秒かかることがあります(体感で8秒前後になることもあります)。ユーザーにとっては「固まった」「真っ白で壊れた」に見えやすいので、ローディング表示はほぼ必須です。
MAUIなら、ActivityIndicatorとWebViewを重ねて、ナビゲーション完了で切り替える形が分かりやすいです。
<Grid>
<WebView x:Name="MyWebView"
Navigating="OnNavigating"
Navigated="OnNavigated" />
<Grid x:Name="LoadingLayer"
BackgroundColor="#80000000"
IsVisible="True">
<ActivityIndicator IsRunning="True"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Label Text="読み込み中…"
VerticalOptions="Center"
HorizontalOptions="Center"
Margin="0,60,0,0"
TextColor="White" />
</Grid>
</Grid>
void OnNavigating(object sender, WebNavigatingEventArgs e)
{
LoadingLayer.IsVisible = true;
}
void OnNavigated(object sender, WebNavigatedEventArgs e)
{
LoadingLayer.IsVisible = false;
if (e.Result != WebNavigationResult.Success)
{
// ここでエラー表示や再読み込みボタンを出すと親切
}
}
エミュレーターでだけ失敗する場合の切り分け
「エミュレーターでは真っ白だが実機では表示できる」ケースもあります。原因は1つに決め打ちできませんが、以下のような差で起きがちです。
- エミュレーターのWebViewコンポーネントやキャッシュ状態が不安定
- ネットワーク(DNS/プロキシ/HTTPS検証)の差
- Google Play開発者サービスやWebView実装の差
切り分けとしては、WebViewのキャッシュクリア、別APIレベル、実機での確認、そしてファイルURLが外部から取得可能かの再確認が有効です。
Office Onlineで「表示できるファイル/できないファイル」が分かれる理由
「Office OnlineのURLを使うと表示できるファイルとできないファイルがある」という相談は非常に多いです。多くの場合、ファイルそのものよりも“ファイルURLの条件”が原因になります。
| 症状 | ありがちな原因 | チェック方法 | 対処例 |
|---|---|---|---|
| ずっと読み込み中/真っ白 | URLが認証必須、IP制限、期限切れ、外部から到達不可 | 端末のブラウザではなく、別ネットワーク/PCから直接ダウンロードできるか | 公開URLにする、SAS期限・権限見直し、リダイレクトを減らす |
| 「ファイルが見つからない」系の表示 | URLエンコードが不正、二重エンコード、特殊文字 | srcに入れる前後でURLが変形していないか | Uri.EscapeDataStringで1回だけエンコード |
| 一部だけ表示崩れ | マクロ付き、パスワード保護、複雑な機能、外部参照 | シンプルな.xlsxで再現するか | PDF化、シート構成を簡素化、閲覧要件を調整 |
| 表示にやたら時間がかかる | ファイルサイズが大きい、シート数が多い、画像/グラフが多い | 小さなファイルで同じ方式が安定するか | ローディングUI、ページ分割、PDF化 |
「キャッシュにダウンロードしてローカルから開く」はなぜ難しいのか
「いったん端末のキャッシュ(FileSystem.CacheDirectoryなど)に落として、そこからWebViewで開けないか?」という発想は自然ですが、ここで壁になるのが“WebViewはExcelを解釈できない”という根本問題です。
- ファイルをローカルに保存できても、WebViewが.xlsxを描画してくれるわけではありません。
- オンラインビューアは基本的にfile:// のローカルパスを読み取りません(セキュリティ上、外部サービスが端末内のファイルにアクセスできないため)。
つまり、「ローカルに落とす」だけでは解決にならず、やるなら次のような構成検討が必要になります。
| やりたいこと | 現実的な構成 | 難所 | おすすめ度 |
|---|---|---|---|
| オンラインビューアを使いつつ、ダウンロード済みを使いたい | アプリ内で簡易HTTPサーバーを立て、localhostで配信→そのURLをビューアに渡す | ビューア側がlocalhostを取得できない/ブロックする可能性、実装が増える | 低 |
| オフラインで閲覧したい | Excel→PDF/HTMLに変換して保存し、その成果物を表示する | 変換処理(サーバー/アプリ)の設計が必要 | 中〜高 |
| Excelそのものを端末で表示したい | 専用ライブラリで解析・描画、または外部アプリで開く | 開発・容量・メンテが重い、表示品質の作り込みが大変 | 要件次第 |
ローカルに保存して「外部アプリで開く」なら実装は可能
「WebView内ではなくてもいいので、端末に落としてExcelアプリで開きたい」なら話は別で、これは比較的素直に実装できます。たとえばHttpClientでダウンロードしてキャッシュに保存し、共有(Share)やLauncherで外部アプリに渡す方式です。
ただしこの記事の主題である「WebView内でプレビュー」とは別解になるため、要件が変わる場合にのみ検討してください。
外部サービスに依存せずに開きたい場合の現実的な選択肢
Google/Microsoftのオンラインビューアに依存せず、アプリ内で完結させたい場合は、“表示”と“解析”は別問題だと理解しておくと設計がぶれません。Excelを読み込むだけならC#のライブラリで可能でも、画面に「Excelっぽく」描画するのは別の実装が必要です。
ライブラリ組み込みのコスト感
例としてJava系のApache POIのようなライブラリを使ってExcelを解析しようとすると、依存関係まで含めて数十〜数百MB規模でアプリサイズが増える可能性があります。さらに、.NET MAUI(C#)からJavaライブラリを扱うにはバインディングやブリッジが必要になり、実装・保守コストも跳ね上がります。
現実的な落としどころ
- 閲覧専用ならPDF化:レイアウト再現性が高く、ビューアも豊富です。
- 表として見られれば十分ならHTML化:シート→HTMLテーブルに変換してWebViewに表示できます(ただしグラフや高度な装飾は難しい)。
- どうしてもExcelそのままが必要なら専用SDK:本格的なオフライン表示や高忠実度が必要な領域です。
| 要件 | おすすめ | 理由 |
|---|---|---|
| 「とにかくWebView内で見えればOK」 | Google Docs Viewer / Office Online Viewer | 実装が軽く、短期間で安定しやすい |
| 機密文書で外部にURLを渡せない | サーバー側でPDF化して配信 | 外部ビューア依存を排除しやすく、アクセス制御も統一できる |
| 完全オフライン必須 | Excel→PDF/HTMLを事前生成して端末に保持 | 端末側でのレンダリング負荷を抑えつつオフライン閲覧が可能 |
| 編集まで含めてExcel互換が必要 | 外部アプリ連携(Office/Sheets等)または専用SDK | WebViewでの再現は難易度が跳ね上がる |
WebView設定をいじるときのセキュリティ注意点
AndroidでAllowFileAccessFromFileURLsやAllowUniversalAccessFromFileURLsを有効にすると、ローカルファイル経由のアクセス範囲が広がります。ドキュメント表示のために設定を盛る場合は、次の点を意識すると安全です。
- 可能なら該当画面だけに限定し、アプリ全体で恒久的に有効化しない
- ユーザー入力のURLをそのまま読み込まない(ホワイトリストやドメイン制限を検討)
- 混在コンテンツ(http)を許可しない運用に寄せる
運用で困らないためのチェックリスト
実装後に「特定環境だけ真っ白」「特定ファイルだけ出ない」といったトラブルを最短で潰すための確認項目をまとめます。
- ファイルURLはHTTPSか(HTTPだとブロックされる/混在コンテンツ扱いになることがあります)
- URLは外部から直接アクセスできるか(認証・IP制限・期限切れがないか)
- URLエンコードは1回だけ(二重エンコードは失敗の元です)
- 表示に時間がかかる前提でローディングUIを出しているか
- エミュレーターだけの不具合を疑う(実機で再現するか確認)
- 機密文書を外部ビューアに渡していないか(SASトークンの扱い含む)
まとめ
AndroidのWebView単体ではExcelを直接表示できないため、iOSと同じ感覚で「URLを読み込めば見える」は成立しにくいのが実情です。最小コストでWebView内表示を実現するなら、Google Docs ViewerまたはMicrosoft Office Online ViewerにURLを渡して埋め込む構成が現実的です。
一方で、オンライン依存や機密性、オフライン要件が絡むと、PDF/HTMLへの変換や専用SDKの検討が必要になります。まずは要件(閲覧だけか、忠実度はどこまでか、外部サービスに出してよいか)を整理し、その上で最短で安定するルートを選ぶのが成功の近道です。

コメント