はじめに (対象読者・この記事でわかること)

この記事は、Androidアプリ内でExcel(xls)ファイルを開かずに直接印刷したいJava開発者を対象にしています。
特に、

  • 帳票データをExcelで受け取り「そのまま印刷」したい
  • サーバ側でPDF変換を挟みたくない
  • 印刷設定(用紙、倍率、色モノクロ)をアプリ側で制御したい

という要望を持つ方に最適です。
読み進めることで、jExcelApiを使ったxls読み込み→Bitmapレンダリング→PrintManager経由での印刷まで、実装レベルで全体像が掴めます。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。

  • Android StudioでのJavaプロジェクト作成・ビルド経験
  • Android 4.4以降のPrintManager/PrintDocumentAdapterの基礎
  • Excelブック=ワークシート=セルの概念
  • Gradleでの依存追加方法

なぜ「xlsをそのまま印刷」が面倒なのか

Android標準SDKには、Excelを扱うAPIが存在しません。
PlayStoreにある「Excel Viewer」アプリは、MicrosoftやGoogleのオフィスアプリにIntentを委譲するため、印刷設定を自社アプリ内で完了させることができません。
さらに、xlsx形式ならApache POIが使えますが、レガシーなxls(BIFF8)形式はPOIのHSSFより軽量なjExcelApiの方が、Android上でメモリ不足になりにくいという事情もあります。
本記事では、これらの課題をクリアする「xls→自前レンダリング→印刷」までの一連の実装を解説します。

ステップバイステップで実装する

ステップ1:jExcelApiを導入してxlsを読み込む

  1. 依存を追加
    2025年6月時点でJCenterが廃止されているため、JitPack経由が安定しています。
    gradle repositories { maven { url 'https://jitpack.io' } } dependencies { implementation 'com.github.ixion:jexcelapi:2.6.13' }

  2. 読み込みクラスを作成
    ワークブックを開き、最初のシートを取得します。
    java Workbook workbook = Workbook.getWorkbook(new File(xlsPath)); Sheet sheet = workbook.getSheet(0); int rows = sheet.getRows(); int cols = sheet.getColumns();

  3. セル単位でBitmapに描画
    セルの内容をCanvasに書き込み、1枚のBitmapとして保持します。
    java Bitmap bitmap = Bitmap.createBitmap(cols * CELL_WIDTH, rows * CELL_HEIGHT, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { String txt = sheet.getCell(c, r).getContents(); canvas.drawText(txt, c * CELL_WIDTH, (r + 1) * CELL_HEIGHT, paint); } }

ステップ2:PrintDocumentAdapterを実装する

  1. 印刷ジョブを開始
    PrintManagerに対して、独自のPrintDocumentAdapterを登録します。
    java PrintManager mgr = (PrintManager) context.getSystemService(PRINT_SERVICE); mgr.print("xls-report-job", new XlsPrintAdapter(bitmap), null);

  2. onLayoutでページ数を確定
    用紙サイズ(A4)と倍率を考慮し、縦に何枚に分かれるか計算します。
    java @Override public void onLayout(PrintAttributes old, PrintAttributes newAttr, CancellationSignal cancel, LayoutResultCallback callback, Bundle extras) { PrintDocumentInfo info = new PrintDocumentInfo .Builder("report.xls") .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) .setPageCount(pageCount) .build(); callback.onLayoutFinished(info, true); }

  3. onWriteでページごとにBitmapを描画
    今回は1シートを1枚のBitmapに展開済みなので、ページ番号に応じてクリップ領域を切り出して出力します。
    java @Override public void onWrite(PageRange[] pages, ParcelFileDescriptor dest, CancellationSignal cancel, WriteResultCallback callback) { PrintedPdfDocument pdf = new PrintedPdfDocument(context, newAttr); for (int i = 0; i < pageCount; i++) { PdfDocument.Page page = pdf.startPage(i); // 1ページ分をBitmapとして描画 Matrix m = new Matrix(); m.postScale(scale, scale); page.getCanvas().drawBitmap(bitmap, m, null); pdf.finishPage(page); } try (FileOutputStream os = new FileOutputStream(dest.getFileDescriptor())) { pdf.writeTo(os); } catch (IOException e) { /* エラーハンドリング */ } pdf.close(); callback.onWriteFinished(pages); }

ハマった点・エラー解決

現象 原因 対処
java.lang.NoClassDefFoundError: jxl.Workbook jExcelApiがmultidexに対応していない android.enableR8.fullMode=falseを一時的に無効化
印刷プレビューで文字化け 日本語フォントが存在しない アセットにNotoSansCJKを配置し、Typeface.createFromAssetで明示的に読み込む
OutOfMemoryError シートが大きすぎてBitmap展開時にメモリ不足 1000行を超える場合は、縦方向に複数のBitmapに分割してから印刷ジョブを発行

まとめ

本記事では、AndroidでExcel(xls)データを「アプリ内完結」で印刷する手法を解説しました。

  • jExcelApiを使った軽量xls読み込み
  • Bitmapレンダリング+PrintManager連携
  • ページ分割・メモリ対策のポイント

これにより、サーバでPDF変換を用意せず、オフライン環境でも帳票印刷が可能になります。
次回は「xlsx対応」「印刷履歴の永続化」「暗号化xlsの復号&印刷」に挑戦したいと思います。

参考資料