2
3

More than 1 year has passed since last update.

【React Native】AndroidのWebViewでPDFを表示する3つの方法

Last updated at Posted at 2022-01-18

はじめに

アプリ内にPDFのドキュメントを置きたい場合、ブラウザ遷移による表示とアプリ内でのWebView表示の2パターンが考えられます。
リンクからブラウザ遷移させるのが実装としては一番楽ですが、ブラウザからアプリに戻るのが面倒であるため、ユーザの手間を考えるとなるべくこの方法は使いたくありません。

そうなると、WebViewでの表示一択となりますが、ここで1つ問題があります。
それはAndroidではWebViewにおけるPDF表示に非対応であるということです。

この問題を回避してAndroidでもアプリ内でPDFを表示する方法を2つ記載します。

Google Docs Viewerの使用

1つ目は、Google Docs Viewerを使って、PDFをページ内に埋め込んで表示する方法です。

AndroidのときだけURLをエンコードして、Google Docs ViewerのURLに埋め込むような関数viewerUri()を作成します。

import { Platform } from "react-native";

export const viewerUri = (uri: string) => {
  if (Platform.OS === "android") {
    const encodeUri = encodeURI(uri);
    return `https://docs.google.com/viewer?url=${encodeUri}&embedded=true`;
  }
  return uri;
};

呼んできたuriを元にWebViewを表示するようなテンプレート WebViewTemplateを作成します。

export const WebViewTemplate = ({ route }) => {
  const { uri } = route.params;

  return <WebView source={uri} />;
};

WebViewTemplateの呼び出し元でviewerUri()を使用します。

  navigate("WebViewTemplate", {
    uri: viewerUri(<path>),
    title: <title>,
  });

これでAndroidのWebViewでPDFを表示できるようになったのですが、実際に実機を触ってみるとPDFのファイルサイズによっては開くのに数秒以上かかってしまっており、「いつ開くんだよ...(イライラ)」という感情が生じてしまいます。
UXを考慮するとこれが結構見過ごせないレベルのモタつきだったので、別の方法(2つ目)を模索することになりました。

rn-pdf-reader-jsの使用

2つ目は、rn-pdf-reader-jsというライブラリに頼る方法です。

expo install rn-pdf-reader-jsでインストールしたら、テンプレート PdfViewTemplateに以下のように記述します。

import React, { useCallback, useState } from "react";
import { StyleSheet } from "react-native";
import PDFReader from "rn-pdf-reader-js";
import { LoadingIcon } from "src/components/molecules/LoadingIcon"

export const PdfViewTemplate = ({ route }) => {
  const { uri } = route.params;
  const [isLoading, setIsLoading] = useState(true);
  const handleOnLoadEnd = useCallback(() => setIsLoading(false), []);

  return (
    <>
      <PDFReader
        source={{ uri }}
        style={StyleSheet.absoluteFill}
        noLoader
        onLoadEnd={handleOnLoadEnd}
      />
      {isLoading && <LoadingIcon style={[StyleSheet.absoluteFill, styles.loading]} />}
    </>
  );
};

const styles = StyleSheet.create({
  loading: {
    justifyContent: "center",
    alignItems: "center",
  },
});

Google Docs Viewerを使用するときよりも表示速度は速くなりますが、それでも1~2秒は描画に時間がかかります。
そんなときにローディングアイコン(クルクルしたやつ)を出したくなると思いますが、PDFReaderにはすでにそのアイコンが実装されています。

中には自分でカスタムしたアイコンを出したい方もいると思いますが、そんな場合には、以下のようにisLoadingというstateを用意して、PDFReaderonLoadEndというpropsでローディングの終了を取得するようにすればOKです。

URLのエンコードは必要ないので、呼び出し元にはパスをそのまま記述します。

  navigate("PdfViewTemplate", {
    uri: <path>,
    title: <title>,
  });

これでモタつきなくPDFを開けるようになりました。

react-native-pdf-viewの使用

rn-pdf-reader-jsでPDFの表示は速くなったのですが、今度はAndroid側のページ操作がスクロールではなく、矢印タッチになってしまいました。
iOSとAndroidのUIの差分が気になるだけではなく単純に操作がしづらいので、これらの問題を解消するためにはまた別のライブラリreact-native-pdf-viewを利用する必要があります。
ただ、こちらをExpoのプロジェクトに導入するためには、ejectでBare workflowに変更する必要があるため、あくまで奥の手となります。

最後に

よりよい方法をご存知の方がいらっしゃいましたら、コメント欄で教えていただければ幸いです。

参考資料

2
3
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
2
3