0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Flutter】AndroidでWebのPDFをDLフォルダに保存せずに閲覧しつつ、必要な時は保存する

Last updated at Posted at 2025-02-06

きっかけ

まだ flutter 初心者の域を脱していない(と思う1)んですが、有難いことに簡単な Android アプリの製作依頼2を頂きまして、その中で下記のような要件が出てきました。

  • Web上のPDFを開きたい
  • 閲覧しかしないときは都度DLフォルダに保存しないでほしい
  • 一方でファイルが必要になる場合もある(メール添付とか)ので、その際はDLフォルダに保存もできるようにしてほしい

iOSやデスクトップ版なら普通に url_launcher とかでデフォルトのブラウザでPDF開けばいいだけ(内蔵のPDFビューアでいずれの要件もカバーできる)なのでそれ以外に特段何かする必要はないんですが
Android だとデフォルトのブラウザである Chrome に内蔵ビューアがなく3 開こうとすると都度DLフォルダに保存してしまうので、それを回避するために行ったことの記録になります。

結論としては極めて当たり前のことしかやってない/書いてないのですが、目先に集中していると意外とこういうことってすぐに思いつかなかったりするので4、同様の要件に直面した方のコロンブスの卵?になることももしかしたらあるかもしれないと思い一応記事にしておきました。

環境

$ flutter doctor
[√] Flutter (Channel stable, 3.24.4, on Microsoft Windows [Version 10.0.19045.5371], locale ja-JP)
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.3.6)
[!] Android Studio (version 2021.3)
    X Unable to determine bundled Java version.
[√] Android Studio (version 2024.1)
[√] VS Code (version 1.96.3)
[√] VS Code, 64-bit edition (version 1.64.2)
[√] Connected device (3 available)
[√] Network resources

やったこと

をコードと共に列記すると、

① URLが .pdf で終わる、もしくは .pdf? を含むかでPDFか否かを判定5
platform が Android 且つURLがPDFだった場合PDF表示画面に遷移する
③ 上記以外の場合はURLを url_launcher で開く

import 'package:url_launcher/url_launcher.dart';

final url = "https://url.for.webpage.or.pdffile";
final isPdf = url.endsWith('.pdf') || url.contains('.pdf?');  // <= 1
if (Platform.isAndroid && isPdf) {
  Navigator.push(context, MaterialPageRoute(
    builder: (context) => PdfScreen(url: url)
  ));  // <= 2
} else if (await canLaunchUrl(Uri.parse(url))) {
  launchUrl(Uri.parse(url));  // <= 3
} else {
  // エラー処理・表示
}

④ PDF表示画面はPDFビューアパッケージのウィジェットによるPDF表示と、DLボタンを設けたAppBarで構成
⑤ DLボタンが押された際はそのPDFを 改めて url_launcher で開く

pdf_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_cached_pdfview/flutter_cached_pdfview.dart';
import 'package:url_launcher/url_launcher.dart';

class PdfScreen extends StatelessWidget {
  const PdfScreen({super.key, required this.url});

  final String url;

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(
      title: Text('PDF表示'),  // <= 何でもOK、可変にしたければメンバ変数とコンストラクタ引数を追加して外から与える
      actions: [
        IconButton(  // アイコンの種類・色はお好みで
          icon: Icon(Icons.file_download_outlined, color: Colors.white),
          onPressed: () async => await launchUrl(Uri.parse(url))  // <= 5
        )
      ]
    ),
    body: PDF(
      backgroundColor: Colors.grey  // PDF表示の設定もお好みで
    ).fromUrl(url)
  );
}

ミソは で、問答無用にDLフォルダへ保存したくないから url_launcher でのオープンを一度は回避したわけですが、でもやっぱり保存したいのなら改めてそれで開けばいいじゃん、と。
DL(指定)フォルダへの保存が要件といわれるとPDFファイルをバイト列でGETするようhttpリクエストを送り、それをファイルに保存するコードを書いて・・・とか考えてしまいがちですが4
昨今の Android ではダウンロードフォルダにアプリからアクセスするのも一筋縄ではいかない6ようなので、それを完璧にやってくれる別のアプリ=Chrome があるならそれに任せるのが話が早かったです。(すぐには思い至りませんでしたorz)

あと補足があるとすれば、PDFを表示する flutter パッケージはいくつもありましたが
今回はWeb上のPDFを直接表示できる上に使用方法もURLを与えるだけと簡単な flutter_cached_pdfview を用いました。

他のビューアを用いる場合は body のところを各々の表示コードに置き換えてください。
遷移元が前述1~3のコードのみである場合、Android でしかこの画面には到達せずプラットフォーム依存の縛りも小さいので、Android で実績のあるPDFビューアならどれでも適応できるんじゃないかとは(未確認ですが)思います。

ちなみに

Android + Chorme でPDFをDLせず表示するには Googleドライブで開く:具体的にはPDFのURLの前に https://docs.google.com/viewer?url= を付してアクセスする――という方法もあり、上手く開ければドライブの表示ページからDL・保存もできるのですが
Googleアカウントでのログインが必要なのと7、何故か表示失敗(グレー一色になる:エラー表示等は特になし)が多発したので断念しました。
コンソール出力にもこれに関係しそうな内容は見当たらず、原因は突き止められていないので知見をお持ちの方がいらしたら補足頂けますと幸いです。

  1. Riverpod とか Firebase とか使いこなせるようになれば脱せるんでしょうか。今のところ未履修なので勉強して使えるようになりたいです

  2. Android だけなら Kotlin とかでよいのでは…と言われそうですが、将来的なiOS展開も含み持たせておきたいという話があるのと、そもそも私が flutter しか使えない等々の事情で flutter で作ってます

  3. ビューアを組み込まないのは Chrome のポリシーの問題らしいので(情報源失念)、今後も変わることはないものと思われます

  4. ソースは私 2

  5. ガバガバ判定な気もしなくはないですが、今のところこれで特に問題にはなってないのでヨシ!!(現場猫AAry)としてます

  6. アプリ専用フォルダなら簡単(getApplicationDocumentsDirectory())ですが、ファイルビューアから開きたい時(メール添付とか)に階層が深く探しづらい

  7. Androidを使っていればアカウントがないということはないと思いますが、ドライブを普段使用していない場合別途ログインを求められたりはしました

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?