APIキー定義をプロジェクト外部で管理する

概要

少し前にandroidアプリをリリースしようとしたところ、

Google Play Consoleで警告を出されたので記事にしておきます。

APIキーの定義は慎重に

アプリに外部サービス(YouTubeやGoogle Mapなど)を組み込む場合、必ずAPIキーが必要になると思います。

APIキー(文字列)をどのように管理しますか?

私はstring.xmlに定義していました。

この管理方法に対し警告が出されたわけです。

外部サービスは基本的に従量課金制です。

一定量まで無料、それ以上はサービス使用量に応じて課金されます。

外部サービスにアクセスする際に使用されるAPIキーは言わばユーザーアカウント。

APIキーに紐づくユーザーにサービス使用量が加算されるわけです。

そのAPIキーをstring.xmlに定義するとどうなるか?

簡単なアプリ解析でバレてしまうようです。。。

APIキーが漏洩してしまうとそれを悪用してサービスのタダ乗りをされてしまうよ!

ということで警告を出されたのでした。

うかつでした。。。

APIキーを隠匿する2つの方法

APIキーをどのように管理すればいいのか。

APIキーをプロジェクト外部に定義し、プロジェクト起動時にメモリ(変数)に保持させるのがいいようです。

そして、その方法は2つ。

環境変数に定義する方法と外部ファイルに定義方法です。

外部管理方法その1.環境変数に定義する

(1)まずは環境変数にAPIキーをセットします。

コマンドライン操作を使った環境変数の設定方法はこちらを参照してください。

(2)次にbuild.gradle(app)に環境変数の参照処理を定義します。

    defaultConfig {
        minSdk 24
        targetSdk 31
        versionCode 1
        versionName "1.0"

        manifestPlaceholders = [KEY_VALUE: System.getenv("api_key")]
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

上記は環境変数”api_key”の値を変数”KEY_VALUE”に格納しています。

(3)次にAndroidManifest.xmlの定義です。

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"

        <meta-data
            android:name="API_KEY"
            android:value="${KEY_VALUE}" />

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

プロジェクト内で参照できるようメタデータに格納します。

(4)あとは参照するだけです。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val appInfo = getPackageManager().getApplicationInfo(packageName, PackageManager.GET_META_DATA)
        val apiKey = appInfo.metaData.getString("API_KEY")

        val txtSet = findViewById<TextView>(R.id.txtSet)
        txtSet.setText(apiKey)
    }
}

上記では取得した環境変数をテキストに表示させています。

外部管理方法その2.外部ファイルに定義する

(1)まずは定義ファイルを作成します。

ファイル名に任意ですがファイルの格納場所は以下です。

debugとreleaseの2か所に格納します。ファイルは全く同じもので問題ありません。

赤枠の場所にファイルを格納します。

ファイルの格納パス

C:\~\AndroidStudioProjects\プロジェクト名\app\src\release\res\values\

C:\ ~ \AndroidStudioProjects\ プロジェクト名 \app\src\debug\res\values\

定義ファイル

<resources>
    <string name="api_key" templateMergeStrategy="preserve" translatable="false">APIキー</string>
</resources>

上記の”APIキー”の箇所に実際のAPIキーを定義します。

(2) 次にAndroidManifest.xmlの定義です。

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"

        <meta-data
            android:name="API_KEY"
            android:value="@string/api_key" />

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

プロジェクト内で参照できるようメタデータに格納します。

(3)あとは参照するだけです。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val appInfo = getPackageManager().getApplicationInfo(packageName, PackageManager.GET_META_DATA)
        val apiKey = appInfo.metaData.getString("API_KEY")

        val txtSet = findViewById<TextView>(R.id.txtSet)
        txtSet.setText(apiKey)
    }
}

以上がAPIキーの外部管理方法です。

APIキーのstring.xml定義はくれぐれもご注意ください。

,