すべてにもかかわらず、なんとか正しい選択をすることができたすべての人に。
これは、Stackoverflowで広く知られているCommonsWareのMark Murphyによる一連の記事の翻訳であり、書籍「The Busy Coder's Guide to Android Development」、「Android's Architecture Components」の著者でもあります。 一部の用語は特に翻訳されていません。
内部ストレージ
Androidストレージモデルに関しては多くの混乱があります。 ストレージモデルでのAndroid 4.4の変更により混乱は大幅に拡大し、それ以来状況は改善していません。 Stack Overflowや同様のリソースについては、さまざまなAndroidストレージモデルに人々が完全に精通しているわけではないという無数の質問があります。
ユーザーが内部ストレージと考えるもの
デバイスのモデルに応じて、ユーザーは最終的に[設定]-> [デバイスのストレージ]または同等の場所にアクセスし、[内部ストレージ]を説明する画面を表示できます。
ユーザーは、内蔵フラッシュドライブ全体が「内部ストレージ」であると考えています。 幸いなことに、GoogleはAndroid 8.0でこの用語を変更し始め、「内部ストレージ」ではなく「一般ストレージ」に移行しました。
ただし、ユーザーがデバイスをUSBで接続している場合、ユーザーはWindowsエクスプローラーウィンドウなどの場所に「内部ストレージ」を表示できます。
Googleが内部ストレージと見なすもの
残念ながら、ユーザーに表示される内容は、Android SDKが「内部ストレージ」と見なすものと同じではないため、混乱が生じます。 内部リポジトリのAndroidドキュメントを読むと、この説明は少なくとも不明瞭です(この記事の執筆以降、コメントテキストは変更されています)。
ファイルをデバイスの内部メモリに直接保存できます。 デフォルトでは、内部ストレージに保存されているファイルはアプリケーションに対してプライベートであり、他のアプリケーションはユーザー(およびユーザー)にアクセスできません。 ユーザーがアプリケーションをアンインストールすると、これらのファイルは削除されます。
実際、Android SDKは、「内部ストレージ」を、アプリケーションがファイルをホストできるアプリケーション固有の特別なディレクトリとして定義します。 ドキュメントで提案されているように、これらのファイルはデフォルトでアプリケーションの読み取りと書き込みを目的としており、他のアプリケーションでは禁止されています(例外:ルート化されたデバイスでスーパーユーザー権限を持つファイルマネージャーで作業しているユーザーはすべてにアクセスできます)。
コンテキストには、次のような内部リポジトリへのアクセスを可能にするいくつかの基本的なメソッドがあります。
getCacheDir()
-
getDir()
-
getDatabasePath()
-
getFilesDir()
-
openFileInput()
-
openFileOutput()
openOrCreateDatabase()
など、他のメソッドはそれらに依存します。 SQLiteOpenHelper
やSharedPreferences
など、他のクラスもそれらに依存します。
内部ストレージの保存場所...
2012年以前にリリースされたさまざまなブログ投稿、StackOverflowレスポンス、書籍を見ると、アプリケーションの「内部ストレージ」が/data/data/your.application.package.name
あることが通知されます。
いくつかのContextメソッドを使用すると、内部にAndroidによって自動的に作成されるディレクトリがいくつかあります。 たとえば、 getFilesDir()
は、アプリケーションの内部ストレージ内のfiles/
ディレクトリを指すFile
オブジェクトを返します。
内部ストレージはどこに保管されますか...残りの時間
ただし、アプリケーションの内部ストレージは常に指定された場所にあるとは限りません。 開発者にとって、この一連のブログ投稿から学ばなければならないルールが1つあります。
ハードコードパスは絶対にしないでください 。
時々、私は開発者が次のようなことをしているのを見ます:
File f=new File("/data/data/their.app.package.name/files/foo.txt");
これは犯罪ではなく、さらに悪いことです。これは間違いです。
正しい動き、そして以下を書く:
File f=new File(getFilesDir(), "foo.txt");
さらに重要なことに、 内部ストレージは常に同じ場所にあるとは限りません 。 タブレット用のAndroid 4.2と携帯電話用のAndroid 5.0 以降 、個別のユーザープロファイル(個別のユーザープロファイル)の概念があることは注目に値します。 各ユーザーは、独自の「内部ストレージ」を取得します。 上記のディレクトリは引き続きプライマリユーザーに使用されますが、セカンダリアカウントに使用されることは保証されません。
内部ストレージの探索
Android Studio 3.0+のDevice File Explorerツールは、エミュレーターのすべての内部ストレージと、実稼働デバイスのデバッグされたアプリケーションの内部ストレージを表示できます。
コマンドラインで、 run-as
オプションを指定してadb
を使用できます。
たとえば、プライマリユーザーの内部ストレージから開発マシンにデータベースをアップロードするには、次を使用できます。
adb shell 'run-as your.application.package.name cp /data/data/your.application.package.name/databases/dbname.db /sdcard'
以下に注意してください:
- 外部ストレージがデバイスにマウントされる場所に宛先を変更する必要があります(ここでは
/sdcard/
として表示されますが、これはすべてのデバイスで同じではありません) - 古いデバイスでは、
cp
代わりにcat
を使用する必要がある場合があります - ファイルが外部ストレージに配置されたら、
adb pull
を使用してコンピューターにダウンロードするか、他の通常の方法(たとえば、デバイスをディスクとしてマウントする)でアクセスできます。
内部ストレージの制限
古いAndroid 1.xおよび2.xデバイスでは、内部ストレージは通常ファイルシステムの専用セクションにあり、このセクションは通常非常に小さいものでした。 元のAndroidデバイスであるHTC Dream(別名、T-Mobile G1)には、すべてのアプリケーションで使用するための70 MBの巨大な内部メモリがありました(これはタイプミスではありません。当時はメモリをメガバイト単位で測定しました)。
2.3デバイスが登場するまでに、内部ストレージのサイズは1 GBになりました。
内部ストレージが大きくなるにつれて、Android 3.0はストレージモデルを変更しました。 4 GB、8 GB、16 GBなどとしてアドバタイズするデバイスの場合 ストレージスペース。通常、内部ストレージに利用可能なすべてのコンテンツ(既存のコンテンツを除く)がありました。 外部ストレージに関する以下の投稿で、Android 3.0での変更点とストレージモデルへの影響について説明します。
Android 1.xおよび2.xの場合、内部ストレージは小さなファイルにのみ有効であり、他のすべてには外部ストレージを使用する必要がありました。 Android 3.0以降は、ほとんどのデバイスとほとんどのユーザーにとって、内部ストレージは、他のアプリケーションによる通常の使用を目的としないファイルや、アプリケーションに関係なくユーザーがアクセスできるファイルに最適です。 ただし、一部の経験豊富なユーザーは、オンボードフラッシュでさえ、保存したいものには不十分であるため、リムーバブルストレージに切り替えます...これは、 ワームの缶です(メモ)
内部ストレージに関するよくある質問
World-ReadableまたはWorld-Writeableの内部ストレージにファイルを作成する必要がありますか?
ああ、$ GODS、いいえ。 FileProvider
を使用し、このコンテンツをContentProvider
の実装でContentProvider
ます。 その後、少なくとも、あなたのバージョンとは異なり、システム内のアプリケーションがこれらのファイルを破壊する可能性がある場合、Android許可システムを使用してこれらのファイルへのアクセスを制御する機会があります。
さて、 android:sharedUserId
どうですか?
私はアドバイスしません。
android: sharedUserId
は、アプリケーションに使用されるユーザーの論理識別子を示すマニフェストに配置できる属性です。 同じ署名キーで署名し、同じandroid:sharedUserId
を要求する、インストールされている他のアプリケーションは、セキュリティの観点から同じLinuxユーザーを使用します。 その結果、これらの2つのアプリケーションは同じLinuxユーザーに属するため、これらの2つのアプリケーションはお互いのファイルを免責して動作することができます。
この属性は、デバイスメーカー、モバイルオペレーター、または変更されたROMファームウェアの開発者によって事前にロードされたソフトウェアスイートなど、プリインストールされたアプリケーションを対象としています。 特に、アプリケーションを1回インストールするとすぐに、既存のファイルへのユーザーのアクセスをブロックせずに、 android:sharedUserId
値android:sharedUserId
変更することはできません...アプリケーションを実行します。
複数のプロセスがファイルにアクセスする場合、さまざまなリスクがあります。 SQLiteなどの一部のサブシステムには、この問題を解決するためのロジックが組み込まれています。 ただし、ファイルへのアクセスを自分で整理する場合(たとえば、 File
およびJava I / Oを使用)、同時アクセスで何かを行う必要があり、これは困難です。
また、あるアプリケーションが使用しているファイルを削除することにより、あるアプリケーションがアンインストールされる状況を処理する必要があります。 たとえば、アプリケーションとプラグインのセットを使用したハブアンドスポークモデルでは、おそらくそれほど危険ではありません。 アプリケーションがより公平である他のモデルでは、ユーザーが別のアプリケーションを削除することを決めたからといって、アプリケーションのデータを失う余裕はありません。
最後に、あなたは未来が何をもたらすことができるかを知りません。 現在、アプリケーションスイートを密結合スイートとして表示できます。 これらのアプリケーションを購入したり、会社を買収したりする人は、他の方法を希望するかもしれません。 ContentProvider
など、接続がContentProvider
データ共有機能を使用すると、柔軟性がContentProvider
ます。 理想的な世界では、アプリケーションは他のアプリケーションをかなり信頼できるものとして扱う必要がありますが、自分のWebサービスのように常にアクセス可能なリソースとは限りません。
ルート化されたデバイスのユーザーが内部ストレージのファイルにアクセスできないようにするにはどうすればよいですか?
内部ストレージにファイルを入れないでください。 ルート化されたデバイスのユーザーは、デバイスで必要なものにアクセスできるため、ユーザーがデータにアクセスできないようにする唯一の方法は、デバイスにデータを保持しないことです。
一部の開発者は、ルート化されたデバイスのユーザーがこれらのファイルを使用できないように、ハードコードされたパスワードでファイルを暗号化しようとします。 これにより、短時間でスピードバンプの効果が得られます。 必要なのは、アプリケーションのリバースエンジニアリングに関心のある1人だけで、これらのファイルを復号化する方法を決定し、その方法についてブログまたはフォーラムにメッセージを書き込みました。
一般に、ルート化されたデバイスを持っている人は比較的少ない-私はそれらを1%未満と評価している。 私見、ルート化されたデバイスから保護する時間を無駄にするのではなく、より良いアプリケーションの作成にエンジニアリング作業を集中することにより、あなたはより成功します。