たぶん、タイトルは少し誤解を招くものです。私の問題は、2 つの標準 Android プロジェクト間で共有される Android ライブラリ プロジェクトがあることです。1 つはアプリの無料バージョン用で、もう 1 つは有料バージョン用です。ライブラリには現在、URI や列名などのいくつかの静的文字列変数を持つコントラクト クラスを含む、ContentProvider のコードがあります。ここで、ライブラリを使用しているアプリに応じて URI の「権限」を変更したいと考えています。頭に浮かぶ 1 つの解決策は、機関を文字列リソースとして保存し、実行時にその文字列を static final String 変数にロードすることです。ただし、コントラクト クラスにはプライベート コンストラクターがあり、文字列リソースを読み込むための Context オブジェクトがないため、これを行う方法がわかりません。問題を解決するために他にどのようなオプションがありますか?
3 に答える
新しいバージョンのビルド ツールを使用している場合は、より良い解決策があります。権限をアプリケーション ID に関連付けます。${applicationId}
これは、ビルド プロセス中にアプリのアプリケーション ID に展開される を使用して自動的に行うことができます。
<provider
android:name=".MyContentProvider"
android:authorities="${applicationId}.provider"/>
アプリケーション ID がcom.example.app.paid
と であるとしcom.example.app.free
ます。アプリをビルドすると、それに応じて権限がcom.example.app.paid.provider
andになりcom.example.app.free.provider
ます。
コードでプロバイダー機関を参照するには、 を使用しますBuildConfig.APPLICATION_ID + ".provider"
。
ユーザーが両方のバージョンをインストールしようとした場合に備えて、無料版と有料版で異なる権限を使用することは理にかなっています。次のように、マニフェストで 2 つのバージョンに対して異なる機関を定義しています。
<provider
android:name="MyApp.MyProvider"
android:authorities="MyApp.MyProvider.free"
android:grantUriPermissions="true"/>
次に、xml ファイルでプロバイダーを構成します (プロバイダー権限などの構成データが他にもあるため、特別な config.xml ファイルを使用しますが、もちろん string.xml を使用することもできます)。
<string name="my_provider_authority">MyApp.MyProvider.free</string>
このコードは、他の文字列リソースと同様にプロバイダー オーソリティを取得します。コンテキストなしで文字列リソースにアクセスするには、アプリケーション コンテキストを使用します。アプリのどこからでもアプリケーション コンテキストにアクセスできるように、アプリケーション クラスを使用しています (ただし、2 つの例外があります)。
public class MyApplication extends Application {
private static Context sContext;
@Override
public void onCreate() {
super.onCreate();
sContext = this;
}
public static Context getContext() {
return sContext;
}
}
もちろん、マニフェストで MyApplication を定義する必要があります。これにより、アプリのどこからでも文字列やその他のリソースにアクセスできます。ただし、2 つの例外があります。
- コンテンツプロバイダー。ContentProviders は Application の開始前に開始できるため、Application コンテキストを使用できません。ただし、ContentProvider は getContext() を介して独自のコンテキストを取得するため、問題はありません。
- 静的コード: コンテキストは、Android コンポーネント (アクティビティ、フラグメント、BroadcastReceivers、サービスなど) のライフサイクル外では利用できない場合があります。したがって、アプリケーション コンテキストに依存する静的初期化子はお勧めできません。ただし、Android コンポーネントのライフサイクル外でコンテキストを使用することは許可されておらず、コンテキストにアクセスする静的メソッドは常にそのライフサイクル内から呼び出されるため、これも実際の問題ではありません。たとえば、アクティビティが ContentProvider の権限を知る必要がある場合、コントラクト クラスで静的メソッドを呼び出します。その呼び出しは、onCreate() や onStart() などのアクティビティの onXYZ() メソッドのいずれかから行われ、コンテキストが確実に初期化されました。したがって、コントラクト クラスの変数を遅延初期化し、Application.onCreate() が以前に呼び出されたことが明らかな場合にのみ、呼び出し元が変数を取得するようにするだけです。もちろん、アクティビティ内から文字列リソースを直接取得できます。私の方法の真の利点は、他のクラス/オブジェクトのリソースが必要になったときに明らかになります。これらのオブジェクトはまだ一部の Android コンポーネントのライフサイクルに関連付けられていますが、これらすべてのオブジェクトにコンテキストを渡す必要はありません。これは、1) 非常に面倒であり、2) コンテキストをリークすると非常にエラーが発生しやすくなります。メモリ使用量の問題 (Android アプリで最も一般的な問題の 1 つ) につながる可能性があります。もちろん、アクティビティ内から文字列リソースを直接取得できます。私の方法の真の利点は、他のクラス/オブジェクトのリソースが必要になったときに明らかになります。これらのオブジェクトはまだ一部の Android コンポーネントのライフサイクルに関連付けられていますが、これらすべてのオブジェクトにコンテキストを渡す必要はありません。これは、1) 非常に面倒であり、2) コンテキストをリークすると非常にエラーが発生しやすくなります。メモリ使用量の問題 (Android アプリで最も一般的な問題の 1 つ) につながる可能性があります。もちろん、アクティビティ内から文字列リソースを直接取得できます。私の方法の真の利点は、他のクラス/オブジェクトのリソースが必要になったときに明らかになります。これらのオブジェクトはまだ一部の Android コンポーネントのライフサイクルに関連付けられていますが、これらすべてのオブジェクトにコンテキストを渡す必要はありません。これは、1) 非常に面倒であり、2) コンテキストをリークすると非常にエラーが発生しやすくなります。メモリ使用量の問題 (Android アプリで最も一般的な問題の 1 つ) につながる可能性があります。
なぜ権限を変更するのですか?プロバイダーをエクスポートする必要はありません。つまり、アプリを分解しない限り、誰も機関名を見ることさえできませんでした。それでも、プロバイダーにアクセスすることはできません。
それがあなた自身の内部の便宜のためであれば、私は同じ権限を使用しますが、URI に異なるセキュリティを設定します。
要するに、あなたのアイデアは面白いですが、私はそのようにはしません。混乱が多すぎます。