25
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Swift】APIキーをschemeごとに分けつつ、パブリックなリポジトリにキーを公開したくない時

Last updated at Posted at 2016-02-28

2017/10/08 追記:@motoshima1150さんよりご指摘いただいたplistの注意事項について追記しました。重要なご指摘ありがとうございます。

やりたいこと

  • 外部サービスのAPIキーなどの設定値をdebugreleaseのschemeごとに分けたい
  • APIキーなどの設定値を使用するプロジェクトはパブリックなリポジトリなので、APIキーは公開されないようにしたい

この2点を満たせるように設定していきたいと思います。
まずはそれぞれの方法を個別に見ていき、最終的にそれらの方法を組み合わせる形で説明していきます。

APIキーをパブリックリポジトリに公開させない

APIキーなどの設定値をプロジェクトから切り離す方法として、ググるとcocoapods-keysの利用がよく見つかりました。

早速試してみましたが、この方法ではなぜかうまくいかず、、
とりあえずパブリックリポジトリに設定値が公開されなければOKなので、結局のところ以下の手順で実装しました。

  1. Keys.plistを作成し、そこにプロジェクトから切り離す設定値を書く
  2. Keys.plistをgit管理下から外す
  3. プロジェクト内ではKeys.plistから値を取得する

1. Keys.plistを作成し、そこにプロジェクトから切り離す設定値を書く

下記例のようにKeys.plistを作成後、任意の文字列でKeyを設定し(myAPIKeyの部分)、Valueにはプロジェクトで使用する設定値を記入します。(myapikeymyapikeymyapikeyの部分)
スクリーンショット 2016-02-28 11.28.28.png

2.Keys.plistをgit管理下から外す

.gitignoreファイルにKeys.plistを追記しましょう。

.gitignore
Keys.plist

これを忘れると結局公開されます。

3.プロジェクト内ではKeys.plistから値を取得する

最後に、1で設定した設定値をプロジェクトから取得して使用する方法について説明します。

まず、簡単にKeys.plistから値を取得するためにKeyManager.swiftというstructを定義しておきます。

KeyManager.swift
import Foundation

struct KeyManager {
    
    private let keyFilePath = NSBundle.mainBundle().pathForResource("Keys", ofType: "plist")
    
    func getKeys() -> NSDictionary? {
        guard let keyFilePath = keyFilePath else {
            return nil
        }
        return NSDictionary(contentsOfFile: keyFilePath)
    }
    
    func getValue(key: String) -> AnyObject? {
        guard let keys = getKeys() else {
            return nil
        }
        return keys[key]
    }
    
}

これで、プロジェクト内では以下のように使用できます。

if let myAPIKey = KeyManager().getValue("myAPIKey") as? String { // "myAPIKey"は自分で設定したKeys.plistのキー
    print(myAPIKey)
}

現状、1人で一台のMacで開発をしているので、このやり方で特に不自由ないですが、他の人と作業をするような場合はgit管理下にないKeys.plistを別の形で共有しないといけないという手間は出てきます。

※2017/10/08追記
こちらのコメントにてご指摘いただいたように、plistはリソースなので公開後のアプリから中身を見ることができてしまいます。
なので、基本的には外部から見られてはいけない内容を直接書いてしまうことは避けたほうが良いです。

こちらも併せてご参考ください。

外部サービスのAPIキーをdebugreleaseのschemeごとに分けたい

次に、外部サービスのAPIキーのような設定値をschemeごとに分ける方法を見ていきます。

私の場合は、Flurryのアプリケーション登録をreleasedebugで分けたかったので、それぞれのAPIキーを取得し、schemeによってAPIキーを使い分けられるようにしています。

こちらは下記のクラスメソッドさんの記事を参考にさせていただき、User-Definedを使用した方法で実現しました。

[iOS] User-Definedを利用しDebugとReleaseで定義を分ける

やり方は参考記事そのままなので、割愛します。

ちなみに、Objective-Cのマクロ?のような書き方も検討したのですが、個人的にあまりコードがきれいに見えないのでこちらにしました。

前述の2点を組み合わせる

最後に、前述のKeys.plistを使った方法とUser-Definedを使った方法を組み合わせて、表題の要望を実現させます。

概要としては、以下のような流れになります。

【設定方法】

  1. Keys.plistdebug時に使用する設定値とrelease時に使用する設定値を定義
  • User-Defineddebug,releaseそれぞれにKeys.plistで取得する**Keyの文字列**を定義(設定値のAPIキーなどではなく、plistのKey)
  • Info.plistUser-Definedの値を取得するためのKey-Valueを定義

【使用方法】

  • Info.plistからUser-Definedの値を取得
  • User-Definedで取得した値をKeys.plistKeyとして、設定値を取得

それでは、それぞれについて見ていきます。

設定方法

1. Keys.plistdebug時に使用する設定値とrelease時に使用する設定値を定義

下記画像では、例として

  • release scheme で使用する MyAPIKeyRelease
  • debug scheme で使用する MyAPIKeyDebug

の2つのKeyとそれに対応するValueを定義しました。

スクリーンショット 2016-02-28 22.16.59.png

また、前述の通り、このKeys.plistはgit管理下から外しておきます。

2. User-Defineddebug,releaseそれぞれにKeys.plistで取得するKeyの文字列を定義

User-Definedに任意の名前(例ではMyAPIKey)で定義を加えます。
そして、DebugReleaseのそれぞれのvalueに、前工程でKeys.plistに設定したKeyを定義します。

スクリーンショット_2016-02-28_22_26_43.png

3. Info.plistUser-Definedの値を取得するためのKey-Valueを定義

最後に、Info.plistに任意のKey(下の例ではMyAPIKey)をつけ、
そのValueとして$(User-Definedでつけた名前)(例では$(MyAPIKey))を定義します。

スクリーンショット 2016-02-28 22.33.39.png

ここまでで、設定は完了です。

使用方法

使用方法はまずコードで示してみます。
記事前半で作成したKeyManagerのstructを使用しています。

if let keyString = NSBundle.mainBundle().objectForInfoDictionaryKey("MyAPIKey") as? String, myAPIKey = KeyManager().getValue(keyString) as? String {
    print(myAPIKey)
    // release scheme の時は myapikeyreleasemyapikeyrelease
    // debug scheme の時は myapikeydebugmyapikeydebug
}

細かく見てみると、

let keyString = NSBundle.mainBundle().objectForInfoDictionaryKey("MyAPIKey") as? String

の部分でInfo.plistからschemeに応じたUser-DefinedMyAPIKeyの値が取得されます。
仮にschemeがdebugだとしたら、この時点でMyAPIKeyDebugという文字列が取得できます。

次に、

myAPIKey = KeyManager().getValue(keyString) as? String

の部分で、先ほど取得した値(schemeがdebugの場合、keyStringMyAPIKeyDebugが代入されている)をKeyとしてKeys.plistから目的のAPIキーを取得しています。

以上の方法で、表題の目的は解決できました。

最後に

正直なところ、少し回りくどいのでこれがベストなのかは分かりません、、

また、「Info.plistに書いた定義はKeys.plistに書く方がいいかなぁ」とか、「KeyManagerのgetValue、staticでいいかも」とか、
いろいろと思うところはありますが、大筋はこんな感じでやりたいことが実現できたかと思います。

もしいいやり方をご存知の方いらっしゃいましたらご教授ください :raised_hands:

25
20
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?