🪶

Supabase xcconfig URL設定で躓いた!

に公開

環境変数にURL設定するときは/$()/が必要

SwiftUIでSupabaseを使用するときに、URLとANON KEYの設定をするのですが、ハードコーディングだと丸見えになってしまう。以下の記事を参考に設定するが、見落としてたところがあって、/$()/記号をつけないと、コメントアウトされて、https:から文字が切れてしまうようだ!

公式チュートリアルを参考に練習してました。
https://supabase.com/docs/reference/swift/installing

https://zenn.dev/headwaters/articles/ab235faa6a72f1

以下のように設定する。

ENV_URL = https:/$()/wovrjnprtfgyluuaxdte.supabase.co
ENV_ANON_KEY = eyJhbGciOiJI*******************tA5Y

設定手順は参考にしたサイトと同じように行う。テキストの名前がENV_URLとか同じにする。xcconfig読み込むときに、設定ミスって青いアイコンで読み込んでましたが、正しくはグレーのアイコンです。

info.plistはこんな感じになればOK

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>ENV_ANON_KEY</key>
	<string>$(ENV_ANON_KEY)</string>
	<key>ENV_URL</key>
	<string>$(ENV_URL)</string>
</dict>
</plist>

ソースコードはこんな感じで書けば表示できました!

import Supabase
import SwiftUI

struct Instrument: Codable, Identifiable {
    let id: Int
    let name: String
}

// let client = SupabaseClient(supabaseURL: URL(string: "https://wovrjnprtfgyluuaxdte.supabase.co")!, supabaseKey: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9******************A5Y")

private let client: SupabaseClient = {
    let urlString = Bundle.main.object(forInfoDictionaryKey: "ENV_URL") as? String
    let anonKey = Bundle.main.object(forInfoDictionaryKey: "ENV_ANON_KEY") as? String

    guard let urlString, let anonKey, let url = URL(string: urlString), !anonKey.isEmpty else {
        fatalError("Missing or invalid ENV_URL / ENV_ANON_KEY. Check Config.xcconfig and Info.plist bridging.")
    }
    return SupabaseClient(supabaseURL: url, supabaseKey: anonKey)
}()

struct ContentView: View {

  @State var instruments: [Instrument] = []
  let supabase = client
    

  var body: some View {
    List(instruments) { instrument in
      Text(instrument.name)
    }
    .overlay {
      if instruments.isEmpty {
        ProgressView()
      }
    }
    .task {
      do {
        instruments = try await supabase.from("instruments").select().execute().value
      } catch {
        dump(error)
      }
    }
  }
}

#Preview {
    ContentView()
}

Buildした結果表示できた!

練習なのでRLSは無効にしてます🙇

補足情報

グローバルにSupabaseのインスタンスを使いたい場面があった。今のところ思いついたのはこんな感じ。

思いつきで作ったものだが、enumを使用して、どのファイルからも呼び出せるようにしてみた。

import Foundation
import Supabase

enum AppEnvironment {
    private static func stringValue(for key: String) -> String {
        guard let value = Bundle.main.object(forInfoDictionaryKey: key) as? String,
              value.isEmpty == false
        else {
            fatalError("Missing or empty Info.plist value for \(key). Check Config.xcconfig and Info.plist bridging.")
        }
        return value
    }

    static var supabaseURL: URL {
        let urlString = stringValue(for: "ENV_URL")
        guard let url = URL(string: urlString) else {
            fatalError("Invalid ENV_URL '\(urlString)'.")
        }
        return url
    }

    static var supabaseAnonKey: String {
        stringValue(for: "ENV_ANON_KEY")
    }
}

enum SupabaseService {
    static let shared: SupabaseClient = {
        SupabaseClient(
            supabaseURL: AppEnvironment.supabaseURL,
            supabaseKey: AppEnvironment.supabaseAnonKey
        )
    }()
}

こちらがデータ取得用のファイル

import Supabase
import SwiftUI

struct Instrument: Codable, Identifiable {
    let id: Int
    let name: String
}

struct ContentView: View {
    @State private var instruments: [Instrument] = []
    private let supabase = SupabaseService.shared

    var body: some View {
        List(instruments) { instrument in
            Text(instrument.name)
        }
        .overlay {
            if instruments.isEmpty {
                ProgressView()
            }
        }
        .task {
            await loadInstruments()
        }
    }

    private func loadInstruments() async {
        do {
            instruments = try await supabase
                .from("instruments")
                .select()
                .execute()
                .value
        } catch {
            // Surface errors in debug builds to help diagnose misconfiguration.
            #if DEBUG
            dump(error)
            #endif
        }
    }
}

#Preview {
    ContentView()
}

最後に

普段はFlutterで仕事してるのですが、Xcodeを使う機会はありXcodeの知識が必要な場面が多く学ぶためにSwiftUIでアプリを作ったりたまたま見つけた副業で仕事したことがありますが、Xcodeの詳しい設定はまだ知らないことが多く今回は環境変数の設定をやってみて、xcconfigへの理解が増えた気がします。

公式サイトもあったのでリンク貼っておきます。iOSの人ってブログばかり見るので、やはり公式は分かりにくいのか。。。
https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project

Discussion