sharedモジュールのandroidMainの中でContextを取得する方法がわからなかったため、調べてみました。
概要
JetpackライブラリのApp Startライブラリを使うと、アプリの起動時にコンポーネントを初期化することができるようです。
今回はこの仕組みを使って、applicationContext
のグローバル変数を作成します。
コンポーネント初期化子を実装する
Initializer<KLocationContext>
を実装したクラスを作成します。
package klocation
import android.content.Context
import androidx.startup.Initializer
// androidMainの中で参照するContext
internal lateinit var applicationContext: Context
private set
public object KLocationContext
/**
* applicationContextを初期化する
*/
public class KLocationInitializer: Initializer<KLocationContext> {
override fun create(context: Context): KLocationContext {
applicationContext = context.applicationContext
return KLocationContext
}
// KLocationInitializerは他に依存しているクラスがないので空のリストを返す
override fun dependencies(): List<Class<out Initializer<*>>> {
return emptyList()
}
}
マニフェスト エントリを設定する
composeAppモジュールのandroidMainに格納されているAndroidManifest.xmlに以下を追記します。
<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false">
<meta-data android:name="klocation.KLocationInitializer"
android:value="androidx.startup" />
</provider>
</application>
<meta-data android:name
には先ほど作成したコンポーネント初期化子の完全修飾クラス名を指定します。
これでApp StartupのInitializationProviderというコンテンツプロバイダによって、コンポーネント初期化子が呼び出されます。
applicationContextの利用
applicationContextはグローバル変数として定義されているので、そのまま参照することができます。
class AndroidTextSpeech: MyTextSpeech, TextToSpeech.OnInitListener {
private lateinit var textToSpeech: TextToSpeech
// iOSと共通のインターフェースを持つメソッド
override fun speak() {
// Contextを使って、インスタンスを取得する
textToSpeech = TextToSpeech(applicationContext, this)
}
// 以下省略
}
まとめ
他にもContextをDIしたり、applicationContextを初期化するのではなくContextを使用するライブラリをApp Startupで初期化するなど、やり方は色々あるようです。
正解は分かりませんが、この方法が一番分かりやすくて気に入っています。
参考