勉強も兼ねて、個人で開発・公開しているAndroidアプリがあるのですが、そのアプリの中でPDFファイルを出力する機能を実装していました。

Androidアプリが対象とするバージョン(targetSdkVersion)が28(Android Q)までだと正常にPDF出力できていたのですが、29(Android 10)や30(Android 11)に上げるとPDF出力ができず、そのため、targetSdkVersionを上げずに28のままにしていました。

ググっても解決できず放置していたのですが、先日もう一度調べてみたら解決できたので、同じことを悩んでいる方がいるかもしれませんし、自分のブログに書いておきます。

PDF出力できなくなった件の修正

アプリをコンパイルするAPIのバージョン(compileSdkVersion)は29や30にあげても大丈夫だったのですが、targetSdkVersionを29や30に上げると、PDF出力できなくなってしまったことがありました。

事象としては、Androidアプリを実行した際に、そのアプリのPDF出力機能を実行しようとすると、画面が真っ白になってPDFファイルに内容が何も出力されませんでした。特にエラーも出てませんでした。

その当時は調べても原因がわからず、結局諦めてtargetSdkVersionは28のままにしていましたが、先日もう一度調べて見ました。

技術的には、私が実装したAndroidアプリからのPDFファイル出力は

1. 表示したい内容の文字列(String型、HTML形式)を作成する
  ↓
2. webView.loadData()で、webViewに出力したいHTMLを読み込む。
  ↓
3. PrintDocumentAdapterやPrintManagerを使って、webViewで表示した内容をPDFで印刷する

という流れにしていました(参考・・・AndroidのPrintManagerを使って画面を印刷する方法 – Qiita

今回調査したところ、こちらのページ(Android Target29に設定するとWebViewで#以降が表示されない – Qiita)を見つけました。

私もHTMLの中で色を指定する際に「#」を使っていたために、webViewの中に何も表示されなかったと思われます。

最初は、自分の調べ方が甘くて、「Android PDF出力できない」的な調べ方をしていましたが、PDFではなくWebViewの方に原因があったことになりますね。

修正後のソースを一部抜粋するとこんな感じになりました。赤字が修正部分です。

//WebView取得
WebView webView = findViewById(R.id.webView);
 
//PDF出力内容作成
String html = ・・・;
 
//WebViewに出力内容を設定(targetSdkVersion29以降で#文字以降が表示されない問題があるので、base64エンコードする必要がある)
// webView.loadData(html, "text/html; charset=utf-8", "utf-8");
String base64String = Base64.encodeToString(html.getBytes(), Base64.DEFAULT);
webView.loadData(base64String, null, "base64");

 
//印刷ファイルのタイトル
String title = "PDFのファイル名.pdf";
 
//PDFで印刷する
PrintDocumentAdapter printDocumentAdapter = new MyPrintDocumentAdapter(webView.createPrintDocumentAdapter(title));
PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
PrintAttributes attributes = new PrintAttributes.Builder()
    .setColorMode(PrintAttributes.COLOR_MODE_MONOCHROME)
    .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
    .build();
Objects.requireNonNull(printManager).print("プリントジョブ名", printDocumentAdapter, attributes);

おわりに

Androidアプリですが、targetSdkVersionが低いとGooglePlayに登録できなくなることが考えられるので(2020/6時点では28以上だったはず)、どこかでtargetSdkVersionを上げる必要があると思います。

とりあえず、自分が公開している下記アプリはこれでtargetSdkVersionを30まで上げてしまうことできたので、一安心です。(PDF出力をしているのは、生活習慣記録表と残業・勤務時間ログになります)