1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ローカルのみで完結するパスワード付きPDF出力をExpoで作った話

1
Last updated at Posted at 2026-11-05

はじめに

「もしもノート - 家族に伝える記録」という Android アプリを公開しました(買い切り・サーバー送信なしのエンディングノートアプリです)。

このアプリのコア機能が「パスワード付きPDFで家族に情報を渡す」なんですが、クラウド非経由・ローカル処理のみでこれをやろうとすると地味に詰まるポイントがあったので、実装の要点を共有します。

環境・前提

項目 バージョン・詳細
OS Windows 11
フレームワーク Expo (SDK 54) + React Native
言語 TypeScript
暗号化方式 AES-128(パスワード付きPDF)

問題(or 背景)

要件はシンプルで、「アプリ内のデータをPDFにして、パスワードを知っている家族だけが開けるようにする」でした。

ただし前提として、このアプリはデータをどこにも送信しない設計なので、PDF生成・暗号化も完全に端末内で完結させる必要があります。サーバー側でPDFを組み立てて返す、みたいな構成は最初から選択肢に入りませんでした。

原因(というか制約)

Expo のマネージドワークフローだと、ネイティブの暗号化PDFライブラリをそのまま使うのが難しい場面があります。今回は Expo のローカルモジュール機構でネイティブ処理を組み込む方針にしましたが、ここで実際にハマったのが以下の2点です。

  1. ローカルモジュールの autolinking が効かない
    modules/{name}/package.json とアプリ側 package.json の両方に file:./ 参照を書かないと autolinking がスキップされ、requireNativeModule が null を返す。片方だけだと「ビルドは通るが実行時に落ちる」という厄介な失敗モードになる。

  2. podspec / AndroidManifest が無いとEASビルドに組み込まれない
    ローカルの autolinking search 自体は「検出した」と出すのに、podspec(iOS)や AndroidManifest.xml(Android)が無いと EAS Build のバイナリに実体が入らない。ローカルモジュールとして機能させるには合計8ファイルほどを揃える必要がありました。

解決策・実装

ネイティブモジュール側の構成を最終的にこの形にしました(Android 側の例)。

modules/expo-pdf-encryptor/
├── package.json          # file:./ 参照元
├── android/
│   ├── build.gradle
│   ├── src/main/AndroidManifest.xml
│   └── src/main/java/.../PdfEncryptorModule.kt
├── ios/
│   ├── ExpoPdfEncryptor.podspec
│   └── ExpoPdfEncryptor.swift
└── index.ts

Kotlin 側で地味に注意が必要だったのが、ファイルパスの扱いです。file:///... 形式のURIをそのまま File() に渡すとエンコード周りで誤解釈されるケースがあったため、java.net.URI 経由で正規化してから渡すようにしています。

val normalizedPath = java.net.URI(fileUri).path
val file = File(normalizedPath)

ポイント

  • ローカルモジュールは「ファイルを置いた」だけでは動かない。package.json の dependencies 側参照・podspec・AndroidManifest まで揃っているかを実機ビルドで確認する
  • file URI はネイティブ側で直接 File() に渡さず、URI クラスで正規化する
  • 「サーバーに送らない」を前提にすると暗号化・PDF生成・保存まで全部端末内のネイティブ処理に閉じ込める必要があり、設計の自由度は下がるが説明文・プライバシーポリシーがシンプルになるメリットもある

まとめ

  • ローカル完結のパスワード付きPDF出力は Expo のローカルモジュール機構で実装できるが、autolinking の罠が2箇所ある
  • ファイルURIの扱いは Kotlin 側で java.net.URI 正規化を忘れずに
  • 暗号化方式は AES-128 を採用し、要件に対して十分な強度であることを確認したうえでリリースした

参考

作ったアプリ

この記事の内容は「もしもノート - 家族に伝える記録」で使っています。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?