cordova-plugin-file

Android Testsuite Chrome Testsuite iOS Testsuite Lint Test

このプラグインは、デバイス上にあるファイルへの読み取り/書き込みアクセスを可能にするFile APIを実装します。

このプラグインは、次のいくつかの仕様に基づいています。HTML5 File API http://www.w3.org/TR/FileAPI/

Directories and System拡張機能の最新版: http://www.w3.org/TR/2012/WD-file-system-api-20120417/ ただし、プラグインコードのほとんどは、以前の仕様が最新であったときに記述されました: http://www.w3.org/TR/2011/WD-file-system-api-20110419/

また、FileWriter仕様も実装しています: http://dev.w3.org/2009/dap/file-system/file-writer.html

W3C FileSystem仕様はWebブラウザでは非推奨になっていますが、FileSystem APIは、サポートされているプラットフォームリストに記載されているプラットフォームで、ブラウザプラットフォームを除き、このプラグインを使用してCordovaアプリケーションでサポートされています。

プラグインの使用方法のアイデアを得るには、このページの下部にあるサンプルを確認してください。その他の例(ブラウザ中心)については、HTML5 RocksのFileSystemの記事を参照してください。

その他のストレージオプションの概要については、Cordovaのストレージガイドを参照してください。

このプラグインは、グローバルなcordova.fileオブジェクトを定義します。

オブジェクトはグローバルスコープにありますが、devicereadyイベントが発生するまで、アプリケーションでは利用できません。

document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
    console.log(cordova.file);
}

インストール

cordova plugin add cordova-plugin-file

サポートされているプラットフォーム

  • Android
  • iOS
  • OS X
  • Windows*
  • ブラウザ

* これらのプラットフォームは、FileReader.readAsArrayBufferFileWriter.write(blob)もサポートしていません。

ファイルの保存場所

v1.2.0以降では、重要なファイルシステムディレクトリへのURLが提供されています。各URLはfile:///path/to/spot/の形式であり、window.resolveLocalFileSystemURL()を使用してDirectoryEntryに変換できます。

  • cordova.file.applicationDirectory - アプリケーションがインストールされている読み取り専用ディレクトリ。(iOS, Android, BlackBerry 10, OSX, windows)

  • cordova.file.applicationStorageDirectory - アプリケーションのサンドボックスのルートディレクトリ。iOSとWindowsではこの場所は読み取り専用です(ただし、特定のサブディレクトリ[iOSの/Documentsやwindowsの/localStateなど]は読み取り/書き込み可能です)。含まれるすべてのデータは、アプリに対してプライベートです。(iOS, Android, BlackBerry 10, OSX)

  • cordova.file.dataDirectory - (Androidでは、外部メモリを使用する必要がある場合は、.externalDataDirectoryを使用します)内部メモリを使用して、アプリケーションのサンドボックス内の永続的でプライベートなデータストレージです。iOSでは、このディレクトリはiCloudと同期されません(.syncedDataDirectoryを使用してください)。(iOS, Android, BlackBerry 10, windows)

  • cordova.file.cacheDirectory - キャッシュされたデータファイルや、アプリで簡単に再作成できるファイルのディレクトリ。デバイスのストレージが不足すると、OSがこれらのファイルを削除する可能性があります。それにもかかわらず、アプリは、OSがここにあるファイルを削除することに依存すべきではありません。(iOS, Android, BlackBerry 10, OSX, windows)

  • cordova.file.externalApplicationStorageDirectory - 外部ストレージ上のアプリケーションスペース。(Android)。Quirksを参照してください。

  • cordova.file.externalDataDirectory - 外部ストレージ上のアプリ固有のデータファイルを保存する場所。(Android)。Quirksを参照してください。

  • cordova.file.externalCacheDirectory - 外部ストレージ上のアプリケーションキャッシュ。(Android)。Quirksを参照してください。

  • cordova.file.externalRootDirectory - 外部ストレージ(SDカード)のルート。(Android, BlackBerry 10)。Quirksを参照してください。

  • cordova.file.tempDirectory - OSが必要に応じてクリアできる一時ディレクトリ。OSがこのディレクトリをクリアすることに依存しないでください。アプリは常に、該当する場合はファイルを削除する必要があります。(iOS, OSX, windows)

  • cordova.file.syncedDataDirectory - 同期する必要があるアプリ固有のファイル(iCloudなど)を保持します。(iOS, windows)

  • cordova.file.documentsDirectory - アプリにプライベートなファイルですが、他のアプリケーション(Officeファイルなど)にとって意味があります。OSXの場合、これはユーザーの~/Documentsディレクトリであることに注意してください。(iOS, OSX)

  • cordova.file.sharedDirectory - すべてのアプリケーションでグローバルに利用可能なファイル(BlackBerry 10)

ファイルシステムのレイアウト

技術的には実装の詳細ですが、cordova.file.*プロパティが実際のデバイス上の物理パスにどのようにマッピングされるかを知っておくと非常に役立ちます。

iOSファイルシステムのレイアウト

デバイスパス cordova.file.* iosExtraFileSystems r/w? 永続的? OSクリア 同期 プライベート
/var/mobile/Applications/<UUID>/ applicationStorageDirectory - r N/A N/A N/A はい
   appname.app/ applicationDirectory バンドル r N/A N/A N/A はい
      www/ - - r N/A N/A N/A はい
   Documents/ documentsDirectory ドキュメント r/w はい いいえ はい はい
      NoCloud/ - ドキュメント-nosync r/w はい いいえ いいえ はい
   Library - ライブラリ r/w はい いいえ はい? はい
      NoCloud/ dataDirectory ライブラリ-nosync r/w はい いいえ いいえ はい
      Cloud/ syncedDataDirectory - r/w はい いいえ はい はい
      Caches/ cacheDirectory キャッシュ r/w はい* はい*** いいえ はい
   tmp/ tempDirectory - r/w いいえ** はい*** いいえ はい

* ファイルはアプリの再起動とアップグレード後も保持されますが、このディレクトリはOSが必要なときにいつでもクリアできます。アプリは、削除される可能性のあるコンテンツを再作成できる必要があります。

** ファイルはアプリの再起動後も保持される可能性がありますが、この動作に依存しないでください。ファイルが更新後も保持される保証はありません。OSがこれらのファイルを削除するタイミング(または削除するかどうか)を保証しないため、アプリは該当する場合はこのディレクトリからファイルを削除する必要があります。

*** OSは必要だと感じたらいつでもこのディレクトリの内容をクリアする可能性がありますが、これに依存しないでください。アプリケーションに適したようにこのディレクトリをクリアする必要があります。

Androidファイルシステムのレイアウト

デバイスパス cordova.file.* AndroidExtraFileSystems r/w? 永続的? OSクリア プライベート
file:///android_asset/ applicationDirectory アセット r N/A N/A はい
/data/data/<app-id>/ applicationStorageDirectory - r/w N/A N/A はい
   キャッシュ cacheDirectory キャッシュ r/w はい はい* はい
   ファイル dataDirectory ファイル r/w はい いいえ はい
      ドキュメント   ドキュメント r/w はい いいえ はい
<sdcard>/ externalRootDirectory sdcard r/w*** はい いいえ いいえ
   Android/data/<app-id>/ externalApplicationStorageDirectory - r/w はい いいえ いいえ
      キャッシュ externalCacheDirectory キャッシュ-外部 r/w はい いいえ** いいえ
      ファイル externalDataDirectory ファイル-外部 r/w はい いいえ いいえ

* OSはこのディレクトリを定期的にクリアする可能性がありますが、この動作に依存しないでください。アプリケーションに適したように、このディレクトリの内容をクリアします。ユーザーがキャッシュを手動でパージすると、このディレクトリの内容は削除されます。

** OSはこのディレクトリを自動的にクリアしません。コンテンツの管理はあなた自身が行う必要があります。ユーザーがキャッシュを手動でパージした場合、ディレクトリの内容は削除されます。

*** API 30以降、これらのディレクトリは書き込み可能ではなくなりました。

: 外部ストレージをマウントできない場合、cordova.file.external*プロパティはnullになります。

Androidの外部ストレージの癖

スコープ付きストレージの導入により、外部ストレージへのアクセスは、File APIを介して信頼性が低くなったり、制限されたりしています。スコープ付きストレージは、API 29で導入されました。既存のアプリはオプトアウトする機能がある場合がありますが、このオプションは新しいアプリでは利用できません。Android API 30以降では、スコープ付きストレージが完全に適用されます。

さらに、API 29では、ダイレクトファイルアクセスサポートされていません。つまり、このプラグインは、API 29デバイスの外部ストレージメディアにアクセスできません

API 30では、FUSEが導入され、File APIを使用して外部ストレージへのアクセスが制限され、このプラグインが再び部分的に機能するようになりました。

制限されたアクセスには、以下が含まれますが、これに限定されません。

  • 適切なREAD_EXTERNALまたはREAD_MEDIA_*パーミッションによる読み取り専用アクセス。
  • 読み取り専用アクセスは、メディアファイルに制限されていますが、ドキュメントには制限されていません。
  • 書き込みは、アプリが所有するファイルのみに制限されています。サードパーティ製アプリが所有するファイル(たとえば、カメラプラグインを使用して作成された画像ファイルなど)を変更することは、File APIではできません。
  • 外部ストレージ内のすべてのパスが書き込み可能であるとは限りません。

これらの制限は、外部ファイルシステム(例: cordova.file.external*パス)にのみ適用されます。cordova.file.dataDirectoryパスなどの内部ファイルシステムには、これらの制限は課されません。

外部ファイルシステムとのインターフェースがアプリケーションの要件である場合は、代わりにMediaStoreプラグインを使用することを検討してください。

OS Xファイルシステムのレイアウト

デバイスパス cordova.file.* iosExtraFileSystems r/w? OSクリア プライベート
/Applications/<appname>.app/ - バンドル r N/A はい
    Content/Resources/ applicationDirectory - r N/A はい
~/Library/Application Support/<bundle-id>/ applicationStorageDirectory - r/w いいえ はい
    ファイル/ dataDirectory - r/w いいえ はい
~/Documents/ documentsDirectory ドキュメント r/w いいえ いいえ
~/Library/Caches/<bundle-id>/ cacheDirectory キャッシュ r/w いいえ はい
/tmp/ tempDirectory - r/w はい* はい
/ rootDirectory ルート r/w いいえ** いいえ

: これはサンドボックス化されていないアプリケーションのレイアウトです。サンドボックスを有効にすると、applicationStorageDirectoryは` ~/Library/Containers/の下になります。/Data/Library/Application Support`。

※ ファイルはアプリの再起動やアップグレード後も保持されますが、このディレクトリはOSが必要に応じてクリアすることがあります。アプリは削除される可能性のあるコンテンツを再作成できるようにする必要があります。また、アプリケーションに適したタイミングでこのディレクトリをクリアする必要があります。

※※ ファイルシステム全体へのアクセスを許可します。これはサンドボックス化されていないアプリでのみ利用可能です。

Windowsファイルシステムレイアウト

デバイスパス cordova.file.* r/w? 永続的? OSクリア プライベート
ms-appdata:/// applicationDirectory r N/A N/A はい
   local/ dataDirectory r/w はい いいえ はい
   temp/ cacheDirectory r/w いいえ はい* はい
   temp/ tempDirectory r/w いいえ はい* はい
   roaming/ syncedDataDirectory r/w はい いいえ はい

※ OSはこのディレクトリを定期的にクリアする可能性があります。

Androidの特異性

Androidの永続ストレージの場所

Androidデバイスに永続ファイルを保存するための有効な場所は複数あります。さまざまな可能性の詳細については、こちらのページをご覧ください。

以前のバージョンのプラグインでは、SDカード(または同等のストレージパーティション)がマウントされているかどうかをデバイスが主張するかに基づいて、起動時に一時ファイルと永続ファイルの場所を選択していました。SDカードがマウントされている場合、または(Nexusデバイスのように)大きな内部ストレージパーティションが利用可能な場合、永続ファイルはその領域のルートに保存されていました。これは、すべてのCordovaアプリがカード上で利用可能なすべてのファイルを見ることができたことを意味します。

SDカードが利用できない場合、以前のバージョンでは/data/data/<packageId>の下にデータを保存していました。これにより、アプリは互いに分離されますが、ユーザー間でデータが共有される可能性は残っていました。

アプリケーションのconfig.xmlファイルで設定することにより、内部ファイルストレージの場所、または以前のロジックを使用してファイルを保存するかどうかを選択できるようになりました。これを行うには、次のいずれかの行をconfig.xmlに追加します。

<preference name="AndroidPersistentFileLocation" value="Internal" />

<preference name="AndroidPersistentFileLocation" value="Compatibility" />

この行がない場合、FileプラグインはデフォルトでInternalを使用します。設定タグが存在し、これらの値のいずれでもない場合、アプリケーションは起動しません。

以前にこのプラグインの古い(3.0.0より前の)バージョンを使用してユーザーにアプリケーションを配布し、永続ファイルシステムにファイルを保存した場合、config.xmlが永続ファイルシステムの場所を指定していない場合は、設定をCompatibilityに設定する必要があります。「Internal」に場所を切り替えると、アプリケーションをアップグレードした既存のユーザーが、デバイスによっては以前に保存したファイルにアクセスできなくなる可能性があることを意味します。

アプリケーションが新しい場合、または以前に永続ファイルシステムにファイルを保存したことがない場合は、一般的にInternal設定が推奨されます。

/android_assetに対する遅い再帰的な操作

Androidでは、アセットディレクトリのリスト表示は非常に遅いです。ただし、Androidプロジェクトのルートにsrc/android/build-extras.gradleを追加することで高速化できます(cordova-android@4.0.0以上も必要です)。

Marshmallowで外部ストレージがマウントされていない場合の書き込み権限

Marshmallowでは、外部の場所に読み書きするときにアプリに権限を要求する必要があります。デフォルトでは、アプリはcordova.file.applicationStorageDirectoryおよびcordova.file.externalApplicationStorageDirectoryへの書き込み権限を持っており、外部ストレージがマウントされていない場合を除き、プラグインはこれらの2つのディレクトリに対する権限を要求しません。ただし、制限により、外部ストレージがマウントされていない場合、cordova.file.externalApplicationStorageDirectoryへの書き込み権限を要求することになります。

SDKターゲットが29未満の場合

公式のAndroid 11のストレージアップデートドキュメントによると、WRITE_EXTERNAL_STORAGE権限はもはや機能せず、アクセスを提供しません。

Build.VERSION_CODES.Q(SDK 29)より前のAPIレベルをターゲットとするアプリでこの権限が許可リストに登録されていない場合、この権限をアプリに付与することはできません。

この権限を追加する必要がある場合は、次の内容をconfig.xmlに追加してください。

<config-file target="AndroidManifest.xml" parent="/*" xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
</config-file>

iOSの特異性

  • cordova.file.applicationStorageDirectoryは読み取り専用です。ルートディレクトリ内にファイルを保存しようとすると失敗します。iOS用に定義された他のcordova.file.*プロパティのいずれかを使用してください(applicationDirectoryapplicationStorageDirectoryのみが読み取り専用です)。
  • FileReader.readAsText(blob, encoding)
    • encodingパラメータはサポートされておらず、常にUTF-8エンコーディングが有効です。

iOSの永続ストレージの場所

iOSデバイスに永続ファイルを保存するための有効な場所は2つあります。DocumentsディレクトリとLibraryディレクトリです。以前のバージョンのプラグインでは、永続ファイルは常にDocumentsディレクトリにのみ保存されていました。これにより、アプリケーションのすべてのファイルがiTunesで表示されるという副作用があり、特にエクスポート用の完全なドキュメントを作成するのではなく、多数の小さなファイルを処理するアプリケーションでは、意図しないことがよくありました。これは、このディレクトリの意図された目的です。

アプリケーションのconfig.xmlファイルで設定することにより、ファイルをDocumentsディレクトリまたはLibraryディレクトリに保存するかどうかを選択できるようになりました。これを行うには、次のいずれかの行をconfig.xmlに追加します。

<preference name="iosPersistentFileLocation" value="Library" />

<preference name="iosPersistentFileLocation" value="Compatibility" />

この行がない場合、FileプラグインはデフォルトでCompatibilityを使用します。設定タグが存在し、これらの値のいずれでもない場合、アプリケーションは起動しません。

以前にこのプラグインの古い(1.0より前の)バージョンを使用してユーザーにアプリケーションを配布し、永続ファイルシステムにファイルを保存した場合、設定をCompatibilityに設定する必要があります。場所をLibraryに切り替えると、アプリケーションをアップグレードした既存のユーザーが、以前に保存したファイルにアクセスできなくなることを意味します。

アプリケーションが新しい場合、または以前に永続ファイルシステムにファイルを保存したことがない場合は、一般的にLibrary設定が推奨されます。

ブラウザの特異性

一般的な特異性と注意点

  • 各ブラウザは、独自のサンドボックス化されたファイルシステムを使用します。IEとFirefoxは、基盤としてIndexedDBを使用します。すべてのブラウザは、パス内のディレクトリ区切り文字としてスラッシュを使用します。
  • ディレクトリエントリは連続して作成する必要があります。たとえば、fs.root.getDirectory('dir1/dir2', {create:true}, successCallback, errorCallback)という呼び出しは、dir1が存在しない場合に失敗します。
  • プラグインは、アプリケーションの初回起動時に永続ストレージを使用するためのユーザー許可を要求します。
  • プラグインはcdvfile://127.0.0.1(ローカルリソース)のみをサポートします。つまり、外部リソースはcdvfile経由ではサポートされていません。
  • プラグインは、「ファイルシステムAPI 8.3命名規則」に従いません。
  • BlobとFileのclose関数はサポートされていません。
  • FileSaverBlobBuilderは、このプラグインではサポートされておらず、スタブもありません。
  • プラグインはrequestAllFileSystemsをサポートしていません。この関数は仕様にも欠落しています。
  • 既存のディレクトリに対してcreate: trueフラグを使用した場合、ディレクトリ内のエントリは削除されません。
  • コンストラクタを介して作成されたファイルはサポートされていません。代わりにentry.fileメソッドを使用する必要があります。
  • 各ブラウザは、blob URL参照に独自の形式を使用します。
  • readAsDataURL関数はサポートされていますが、Chromeのメディアタイプはエントリ名拡張子に依存し、IEのメディアタイプは常に空(これは仕様によるとtext-plainと同じです)、Firefoxのメディアタイプは常にapplication/octet-streamです。たとえば、コンテンツがabcdefgの場合、Firefoxはdata:application/octet-stream;base64,YWJjZGVmZw==を返し、IEはdata:;base64,YWJjZGVmZw==を返し、Chromeはdata:<エントリ名の拡張子によって異なるメディアタイプ>;base64,YWJjZGVmZw==を返します。
  • toInternalURLは、file:///persistent/path/to/entryという形式でパスを返します(Firefox、IE)。Chromeは、cdvfile://127.0.0.1/persistent/fileという形式でパスを返します。

Chromeの特異性

  • Chromeファイルシステムは、デバイスの準備完了イベントの直後には準備ができていません。回避策として、filePluginIsReadyイベントをサブスクライブできます。例
    window.addEventListener('filePluginIsReady', function(){ console.log('File plugin is ready');}, false);
    

    window.isFilePluginReadyRaised関数を使用して、イベントがすでに発生したかどうかを確認できます。

  • window.requestFileSystem TEMPORARYおよびPERSISTENTファイルシステムのクォータはChromeでは制限されていません。
  • Chromeで永続ストレージを増やすには、window.initPersistentFileSystemメソッドを呼び出す必要があります。永続ストレージのクォータはデフォルトで5MBです。
  • Chromeは、file:///プロトコル経由でAPIをサポートするために--allow-file-access-from-files実行引数を必要とします。
  • 既存のEntryを取得するときにフラグ{create:true}を使用すると、Fileオブジェクトは変更されません。
  • Chromeでは、イベントのcancelableプロパティがtrueに設定されます。これは仕様に反します。
  • ChromeのtoURL関数は、アプリケーションホストに応じてfilesystem:プレフィックス付きのパスを返します。たとえば、filesystem:file:///persistent/somefile.txtfilesystem:https://127.0.0.1:8080/persistent/somefile.txtなどです。
  • toURL関数の結果は、ディレクトリエントリの場合、末尾にスラッシュを含みません。ただし、Chromeはスラッシュ付きのURLでディレクトリを正しく解決します。
  • resolveLocalFileSystemURLメソッドでは、インバウンドurlfilesystemプレフィックスが必要です。たとえば、resolveLocalFileSystemURLurlパラメーターは、Androidのfile:///persistent/somefile.txtという形式ではなく、filesystem:file:///persistent/somefile.txtという形式である必要があります。
  • 非推奨のtoNativeURL関数はサポートされておらず、スタブもありません。
  • setMetadata関数は仕様に記述されておらず、サポートされていません。
  • 存在しないファイルシステムを要求すると、SYNTAX_ERR(コード:8)の代わりにINVALID_MODIFICATION_ERR(コード:9)がスローされます。
  • すでに存在するファイルまたはディレクトリを排他的に作成しようとすると、PATH_EXISTS_ERR(コード:12)の代わりにINVALID_MODIFICATION_ERR(コード:9)がスローされます。
  • ルートファイルシステムでremoveRecursivelyを呼び出そうとすると、NO_MODIFICATION_ALLOWED_ERR(コード:6)の代わりにINVALID_MODIFICATION_ERR(コード:9)がスローされます。
  • 存在しないディレクトリにmoveToしようとすると、NOT_FOUND_ERR(コード:1)の代わりにINVALID_MODIFICATION_ERR(コード:9)がスローされます。

IndexedDBベースの実装の特異性(FirefoxとIE)

  • ...はサポートされていません。
  • IEはfile:///モードをサポートしていません。ホストモード(https://127.0.0.1:xxxx)のみがサポートされています。
  • Firefoxのファイルシステムサイズは制限されていませんが、50MB拡張ごとにユーザー許可が要求されます。IE10では、プロンプトなしでファイルシステムのインプリメンテーションで使用されるAppCacheとIndexedDBを合計10MBまで許可します。そのレベルに達すると、サイトごとに最大250MBまで増やすことを許可するかどうかを尋ねられます。したがって、requestFileSystem関数のsizeパラメーターは、FirefoxとIEのファイルシステムには影響しません。
  • readAsBinaryString関数はSpecsに記載されておらず、IEではサポートされておらず、スタブもありません。
  • file.typeは常にnullです。
  • 削除されたDirectoryEntryインスタンスのコールバック結果を使用してエントリを作成しないでください。そうしないと、「ハングエントリ」が発生します。
  • 書き込んだばかりのファイルを読み取る前に、このファイルの新しいインスタンスを取得する必要があります。
  • Spec に記載されていない setMetadata 関数は、modificationTime フィールドの変更のみをサポートします。
  • copyTo 関数と moveTo 関数は、ディレクトリをサポートしません。
  • ディレクトリのメタデータはサポートされていません。
  • Entry.remove と directoryEntry.removeRecursively は、空でないディレクトリを削除する際に失敗しません。削除されるディレクトリは、その内容とともにクリーンアップされます。
  • abort 関数と truncate 関数はサポートされていません。
  • 進捗イベントは発生しません。たとえば、このハンドラーは実行されません。
    writer.onprogress = function() { /*commands*/ };
    

アップグレードに関する注意点

このプラグインの v1.0.0 では、公開されている仕様に合わせて、FileEntry および DirectoryEntry の構造が変更されました。

以前の(1.0.0 より前の)バージョンのプラグインでは、デバイスの絶対ファイルロケーションが Entry オブジェクトの fullPath プロパティに格納されていました。これらのパスは通常、次のような形式でした。

/var/mobile/Applications/<application UUID>/Documents/path/to/file  (iOS)
/storage/emulated/0/path/to/file                                    (Android)

これらのパスは、Entry オブジェクトの toURL() メソッドによっても返されていました。

v1.0.0 では、fullPath 属性は、HTML ファイルシステムのルートに対する相対パスであるファイルのパスです。したがって、上記のパスは両方とも、fullPath が次の FileEntry オブジェクトで表されるようになりました。

/path/to/file

アプリケーションがデバイスの絶対パスを使用しており、以前に Entry オブジェクトの fullPath プロパティを通じてそれらのパスを取得していた場合は、entry.toURL() を使用するようにコードを更新する必要があります。

下位互換性のために、resolveLocalFileSystemURL() メソッドはデバイスの絶対パスを受け入れ、そのファイルが TEMPORARY または PERSISTENT ファイルシステムのいずれかに存在する場合は、それに対応する Entry オブジェクトを返します。

これは特に、デバイスの絶対パスを以前使用していた(そして今でも受け入れることができる)File-Transfer プラグインで問題になっていました。FileSystem URL で正しく動作するように更新されたため、entry.fullPathentry.toURL() に置き換えることで、そのプラグインをデバイス上のファイルで動作させる際の問題が解決されるはずです。

v1.1.0 では、可能な限り絶対 'file://' URL を返すように toURL() の戻り値が変更されました ( CB-6394 を参照)。'cdvfile:'-URL を確実にするには、toInternalURL() を使用できます。このメソッドは、次のような形式のファイルシステム URL を返すようになりました。

cdvfile://127.0.0.1/persistent/path/to/file

これは、ファイルを一意に識別するために使用できます。

v7.0.0 では、アプリのコンテンツが file:// スキームから提供される場合、Android の toURL() の戻り値が絶対 file:// URL を返すように更新されました。

アプリのコンテンツが http(s):// スキームから提供される場合は、代わりに cdvfile 形式の URL が返されます。cdvfile 形式の URL は、内部メソッド toInternalURL() から作成されます。

toInternalURL() が返すファイルシステム URL の例

https://127.0.0.1/persistent/path/to/file

toURL flow

正しい URL が返されるように、常に toURL() を使用することを推奨します。

cdvfile プロトコル

  • Android ではサポートされていません

目的

cdvfile://127.0.0.1/persistent|temporary|another-fs-root*/path/to/file は、プラットフォームに依存しないファイルパスに使用できます。cdvfile パスは、コアプラグインでサポートされています。たとえば、cordova-plugin-file-transfer を介して mp3 ファイルを cdvfile パスにダウンロードし、cordova-plugin-media を介して再生できます。

*注: 利用可能な fs ルートの詳細については、ファイルの保存場所ファイルシステムのレイアウト、およびプラグインの設定を参照してください。

cdvfile をタグの src として使用するには、resolveLocalFileSystemURL を介して取得できる解決済みの fileEntry の toURL() メソッドを介してネイティブパスに変換できます。以下の例を参照してください。

cdvfile:// パスを DOM で直接使用することもできます。たとえば、

<img src="cdvfile://127.0.0.1/persistent/img/logo.png" />

: このメソッドでは、次のコンテンツセキュリティルールを更新する必要があります。

  • インデックスページの Content-Security-Policy メタタグに cdvfile: スキームを追加します。例:
    • <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: cdvfile: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
  • config.xml<access origin="cdvfile://*" /> を追加します。

cdvfile:// をネイティブパスに変換する

resolveLocalFileSystemURL('cdvfile://127.0.0.1/temporary/path/to/file.mp4', function(entry) {
    var nativePath = entry.toURL();
    console.log('Native URI: ' + nativePath);
    document.getElementById('video').src = nativePath;

ネイティブパスを cdvfile:// に変換する

resolveLocalFileSystemURL(nativePath, function(entry) {
    console.log('cdvfile URI: ' + entry.toInternalURL());

コアプラグインで cdvfile を使用する

fileTransfer.download(uri, 'cdvfile://127.0.0.1/temporary/path/to/file.mp3', function (entry) { ...
var my_media = new Media('cdvfile://127.0.0.1/temporary/path/to/file.mp3', ...);
my_media.play();

cdvfile の癖

  • DOM で cdvfile:// パスを使用することは、Windows プラットフォームではサポートされていません (代わりにパスをネイティブに変換できます)。

エラーコードと意味の一覧

エラーがスローされると、次のいずれかのコードが使用されます。

コード 定数
1 NOT_FOUND_ERR
2 SECURITY_ERR
3 ABORT_ERR
4 NOT_READABLE_ERR
5 ENCODING_ERR
6 NO_MODIFICATION_ALLOWED_ERR
7 INVALID_STATE_ERR
8 SYNTAX_ERR
9 INVALID_MODIFICATION_ERR
10 QUOTA_EXCEEDED_ERR
11 TYPE_MISMATCH_ERR
12 PATH_EXISTS_ERR

プラグインの設定 (オプション)

利用可能なファイルシステムのセットは、プラットフォームごとに設定できます。iOS と Android の両方が、config.xmlタグを認識し、インストールするファイルシステムを指定します。デフォルトでは、すべてのファイルシステムルートが有効になっています。

<preference name="iosExtraFilesystems" value="library,library-nosync,documents,documents-nosync,cache,bundle,root" />
<preference name="AndroidExtraFilesystems" value="files,files-external,documents,sdcard,cache,cache-external,assets,root" />

Android

  • files: アプリケーションの内部ファイルストレージディレクトリ
  • files-external: アプリケーションの外部ファイルストレージディレクトリ
  • sdcard: グローバル外部ファイルストレージディレクトリ (SD カードがインストールされている場合は SD カードのルート)。これを使用するには、android.permission.WRITE_EXTERNAL_STORAGE 権限が必要です。
  • cache: アプリケーションの内部キャッシュディレクトリ
  • cache-external: アプリケーションの外部キャッシュディレクトリ
  • assets: アプリケーションのバンドル (読み取り専用)
  • root: デバイスファイルシステム全体
  • applicationDirectory: 制限付きアクセスの読み取り専用。このディレクトリ内のファイルのコピーは可能ですが、直接読み取ると「ファイルが見つかりません」になります。Android は、"files" ファイルシステム内の "/Documents/" サブディレクトリを表す "documents" という名前の特別なファイルシステムもサポートしています。

iOS

  • library: アプリケーションのライブラリディレクトリ
  • documents: アプリケーションのドキュメントディレクトリ
  • cache: アプリケーションのキャッシュディレクトリ
  • bundle: アプリケーションのバンドル。ディスク上のアプリ自体の場所 (読み取り専用)
  • root: デバイスファイルシステム全体

デフォルトでは、ライブラリとドキュメントディレクトリは iCloud に同期できます。library-nosyncdocuments-nosync という 2 つの追加のファイルシステムをリクエストすることもできます。これらは、/Library または /Documents ファイルシステム内の同期されていない特別なディレクトリを表します。

サンプル: ファイルとディレクトリの作成、ファイルの書き込み、読み込み、および追加

File プラグインを使用すると、アプリの一時的または永続的なストレージ場所 (サンドボックス化されたストレージ) にファイルを保存したり、その他のプラットフォームに依存する場所にファイルを保存したりできます。このセクションのコードスニペットは、次の異なるタスクを示しています。

永続的なファイルの作成

File プラグイン API を使用する前に、requestFileSystem を使用してファイルシステムにアクセスできます。この際、永続的なストレージまたは一時的なストレージをリクエストできます。永続的なストレージは、ユーザーによって許可されない限り削除されません。

requestFileSystem を使用してファイルシステムへのアクセスを取得すると、サンドボックス化されたファイルシステムに対してのみアクセスが許可されます (サンドボックスはアプリ自体へのアクセスを制限します)。デバイス上の任意のファイルシステムロケーションへの一般的なアクセスは許可されません。(サンドボックス化されたストレージの外部にあるファイルシステムロケーションにアクセスするには、プラットフォーム固有のロケーションをサポートする window.resolveLocalFileSystemURL などの他のメソッドを使用してください。この一例については、ファイルの追加を参照してください)。

永続的なストレージのリクエストを以下に示します。

WebView クライアント (ブラウザの代わりに) またはネイティブアプリ (Windows) をターゲットとする場合、永続的なストレージを使用する前に requestQuota を使用する必要はありません。

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {

    console.log('file system open: ' + fs.name);
    fs.root.getFile("newPersistentFile.txt", { create: true, exclusive: false }, function (fileEntry) {

        console.log("fileEntry is file?" + fileEntry.isFile.toString());
        // fileEntry.name == 'someFile.txt'
        // fileEntry.fullPath == '/someFile.txt'
        writeFile(fileEntry, null);

    }, onErrorCreateFile);

}, onErrorLoadFs);

成功コールバックは、FileSystem オブジェクト (fs) を受け取ります。fs.root を使用して、ファイルを作成または取得するために使用できる DirectoryEntry オブジェクトを返します (getFile を呼び出すことによって)。この例では、fs.root は、サンドボックス化されたファイルシステムの永続的なストレージを表す DirectoryEntry オブジェクトです。

getFile の成功コールバックは、FileEntry オブジェクトを受け取ります。これを使用して、ファイルの書き込みおよび読み取り操作を実行できます。

一時ファイルの作成

以下は、一時的なストレージのリクエストの例です。一時的なストレージは、デバイスのメモリが不足した場合にオペレーティングシステムによって削除される場合があります。

window.requestFileSystem(window.TEMPORARY, 5 * 1024 * 1024, function (fs) {

    console.log('file system open: ' + fs.name);
    createFile(fs.root, "newTempFile.txt", false);

}, onErrorLoadFs);

一時的なストレージを使用している場合は、getFile を呼び出すことによってファイルを作成または取得できます。永続的なストレージの例と同様に、これにより、読み取りまたは書き込み操作に使用できる FileEntry オブジェクトが提供されます。

function createFile(dirEntry, fileName, isAppend) {
    // Creates a new file or returns the file if it already exists.
    dirEntry.getFile(fileName, {create: true, exclusive: false}, function(fileEntry) {

        writeFile(fileEntry, null, isAppend);

    }, onErrorCreateFile);

}

ファイルへの書き込み

FileEntry オブジェクトを取得したら、createWriter を呼び出すことでファイルに書き込むことができます。これは、成功コールバックで FileWriter オブジェクトを返します。FileWriter の write メソッドを呼び出してファイルに書き込みます。

function writeFile(fileEntry, dataObj) {
    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function (fileWriter) {

        fileWriter.onwriteend = function() {
            console.log("Successful file write...");
            readFile(fileEntry);
        };

        fileWriter.onerror = function (e) {
            console.log("Failed file write: " + e.toString());
        };

        // If data object is not passed in,
        // create a new Blob instead.
        if (!dataObj) {
            dataObj = new Blob(['some file data'], { type: 'text/plain' });
        }

        fileWriter.write(dataObj);
    });
}

ファイルの読み込み

既存のファイルを読み取るには、FileEntry オブジェクトも必要です。FileEntry の file プロパティを使用してファイル参照を取得し、新しい FileReader オブジェクトを作成します。readAsText などのメソッドを使用して、読み取り操作を開始できます。読み取り操作が完了すると、this.result に読み取り操作の結果が格納されます。

function readFile(fileEntry) {

    fileEntry.file(function (file) {
        var reader = new FileReader();

        reader.onloadend = function() {
            console.log("Successful file read: " + this.result);
            displayFileData(fileEntry.fullPath + ": " + this.result);
        };

        reader.readAsText(file);

    }, onErrorReadFile);
}

別のメソッドを使用したファイルの追加

もちろん、多くの場合、新しいファイルを作成するのではなく、既存のファイルに追加することが必要になります。以下はその例です。この例では、window.resolveLocalFileSystemURL を使用してファイルシステムにアクセスする別の方法を示します。この例では、クロスプラットフォームの Cordova ファイル URL である cordova.file.dataDirectory を関数に渡します。成功コールバックは DirectoryEntry オブジェクトを受け取ります。これは、ファイルの作成などのために使用できます。

window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function (dirEntry) {
    console.log('file system open: ' + dirEntry.name);
    var isAppend = true;
    createFile(dirEntry, "fileToAppend.txt", isAppend);
}, onErrorLoadFs);

この使用法に加えて、resolveLocalFileSystemURL を使用して、サンドボックス化されたストレージシステムの一部ではないファイルシステムロケーションにアクセスできます。詳細については、ファイルの保存場所を参照してください。これらのストレージロケーションの多くはプラットフォーム固有です。cdvfile プロトコルを使用して、クロスプラットフォームのファイルシステムロケーションを resolveLocalFileSystemURL に渡すこともできます。

追加操作の場合、前のコードで呼び出される createFile 関数には新しいものはありません (実際のコードについては、前の例を参照してください)。createFilewriteFile を呼び出します。writeFile では、追加操作がリクエストされているかどうかを確認します。

FileWriter オブジェクトを取得したら、seek メソッドを呼び出し、書き込みを行う位置のインデックス値を渡します。この例では、ファイルが存在するかどうかもテストします。seek を呼び出した後、FileWriter の write メソッドを呼び出します。

function writeFile(fileEntry, dataObj, isAppend) {
    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function (fileWriter) {

        fileWriter.onwriteend = function() {
            console.log("Successful file read...");
            readFile(fileEntry);
        };

        fileWriter.onerror = function (e) {
            console.log("Failed file read: " + e.toString());
        };

        // If we are appending data to file, go to the end of the file.
        if (isAppend) {
            try {
                fileWriter.seek(fileWriter.length);
            }
            catch (e) {
                console.log("file doesn't exist!");
            }
        }
        fileWriter.write(dataObj);
    });
}

既存のバイナリファイルの保存

サンドボックス化されたファイルシステムで作成したばかりのファイルに書き込む方法をすでに示しました。既存のファイルにアクセスして、それをデバイスに保存できるものに変換する必要がある場合はどうすればよいでしょうか? この例では、xhr リクエストを使用してファイルを取得し、サンドボックス化されたファイルシステムのキャッシュに保存します。

ファイルを取得する前に、requestFileSystem を使用して FileSystem 参照を取得します。メソッド呼び出しで window.TEMPORARY を渡すことによって (以前と同じ)、返される FileSystem オブジェクト (fs) は、サンドボックス化されたファイルシステムのキャッシュを表します。fs.root を使用して、必要な DirectoryEntry オブジェクトを取得します。

window.requestFileSystem(window.TEMPORARY, 5 * 1024 * 1024, function (fs) {

    console.log('file system open: ' + fs.name);
    getSampleFile(fs.root);

}, onErrorLoadFs);

完全を期すために、Blobイメージを取得するxhrリクエストを以下に示します。このコードには、すでに取得済みのDirectoryEntry参照をsaveFile関数への引数として渡すことを除いて、Cordova固有のものは何もありません。Blobイメージを保存し、後でファイル(操作を検証するため)を読み取った後に表示します。

function getSampleFile(dirEntry) {

    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'https://cordova.dokyumento.jp/static/img/cordova_bot.png', true);
    xhr.responseType = 'blob';

    xhr.onload = function() {
        if (this.status == 200) {

            var blob = new Blob([this.response], { type: 'image/png' });
            saveFile(dirEntry, blob, "downloadedImage.png");
        }
    };
    xhr.send();
}

Cordova 5のセキュリティのため、上記のコードでは、index.htmlのContent-Security-Policy要素にドメイン名https://cordova.dokyumento.jpを追加する必要があります。index.htmlの要素に追加する必要があります。

ファイルを取得した後、内容を新しいファイルにコピーします。現在のDirectoryEntryオブジェクトは、すでにアプリキャッシュに関連付けられています。

function saveFile(dirEntry, fileData, fileName) {

    dirEntry.getFile(fileName, { create: true, exclusive: false }, function (fileEntry) {

        writeFile(fileEntry, fileData);

    }, onErrorCreateFile);
}

writeFileでは、BlobオブジェクトをdataObjとして渡すと、新しいファイルに保存されます。

function writeFile(fileEntry, dataObj, isAppend) {

    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function (fileWriter) {

        fileWriter.onwriteend = function() {
            console.log("Successful file write...");
            if (dataObj.type == "image/png") {
                readBinaryFile(fileEntry);
            }
            else {
                readFile(fileEntry);
            }
        };

        fileWriter.onerror = function(e) {
            console.log("Failed file write: " + e.toString());
        };

        fileWriter.write(dataObj);
    });
}

ファイルへの書き込み後、それを読み取り表示します。イメージはバイナリデータとして保存されているため、FileReader.readAsArrayBufferを使用して読み取ることができます。

function readBinaryFile(fileEntry) {

    fileEntry.file(function (file) {
        var reader = new FileReader();

        reader.onloadend = function() {

            console.log("Successful file write: " + this.result);
            displayFileData(fileEntry.fullPath + ": " + this.result);

            var blob = new Blob([new Uint8Array(this.result)], { type: "image/png" });
            displayImage(blob);
        };

        reader.readAsArrayBuffer(file);

    }, onErrorReadFile);
}

データを読み取った後、次のようなコードを使用してイメージを表示できます。window.URL.createObjectURLを使用して、BlobイメージのDOM文字列を取得します。

function displayImage(blob) {

    // Displays image if result is a valid DOM string for an image.
    var elem = document.getElementById('imageFile');
    // Note: Use window.URL.revokeObjectURL when finished with image.
    elem.src = window.URL.createObjectURL(blob);
}

イメージファイルの表示

FileEntryを使用してイメージを表示するには、toURLメソッドを呼び出すことができます。

function displayImageByFileURL(fileEntry) {
    var elem = document.getElementById('imageFile');
    elem.src = fileEntry.toURL();
}

FileEntryの代わりにプラットフォーム固有のURIを使用しており、イメージを表示したい場合は、index.htmlのContent-Security-Policy要素にURIのメイン部分を含める必要がある場合があります。index.htmlの要素に含める必要があります。たとえば、Windows 10では、ms-appdata:要素に含めることができます。以下に例を示します。

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: ms-appdata: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">

ディレクトリの作成

ここに示すコードでは、アプリのストレージ場所のルートにディレクトリを作成します。このコードは、書き込み可能なストレージ場所(つまり、任意のDirectoryEntry)で使用できます。ここでは、この関数にfs.rootを渡すことで、アプリケーションキャッシュに書き込みます(FileSystemオブジェクトを取得するためにwindow.TEMPORARYを使用したと仮定します)。

このコードは、アプリケーションキャッシュに/NewDirInRoot/imagesフォルダーを作成します。プラットフォーム固有の値については、「ファイルシステムレイアウト」を参照してください。

function createDirectory(rootDirEntry) {
    rootDirEntry.getDirectory('NewDirInRoot', { create: true }, function (dirEntry) {
        dirEntry.getDirectory('images', { create: true }, function (subDirEntry) {

            createFile(subDirEntry, "fileInNewSubDir.txt");

        }, onErrorGetDir);
    }, onErrorGetDir);
}

サブフォルダーを作成する場合は、上記のコードに示すように、各フォルダーを個別に作成する必要があります。