Google Drive を使って Swift/Kotlin アプリに JSON データを配信する方法
はじめに
個人開発では、できるだけお金をかけずに済ませたい。そこで試行錯誤の末にたどり着いたのが、Google Drive をファイルサーバー代わりに使うという方法である。
Google Drive API という選択肢も勿論あるが、この記事で紹介する方法は、面倒な設定なしで静的ファイルのホスティングができる、最も簡単な方法 だと思う。
この方法を用いてiOS のネイティブアプリで1年以上運用しているが、今のところ一度も問題が起きたことはない。最近Kotlinでも動作確認が取れたので、このタイミングで記事にまとめることにした。
ステップ1:JSON ファイルを用意する
まずは任意の JSON データを用意する。例として以下のような locations.json ファイルを想定する。
[
{"name": "Tokyo", "lat": 35.6895, "lng": 139.6917},
{"name": "Osaka", "lat": 34.6937, "lng": 135.5023}
]
ステップ2:Google Drive にアップロードしてファイルIDを確認
-
Google Drive にログインし、
locations.jsonをアップロードする。 - ファイルのアクセス権限を「リンクを知っている全員」に変更する。
- クリップボードに URL をコピーする。
このときコピーされるリンクは、以下のような形式になっているはず。
https://drive.google.com/file/d/xxxxxxxxxx/view?usp=share_link
この中の xxxxxxxxxx がファイル ID
ステップ3:リンクを直接ダウンロード用の URL に変換する
以下のように書き換えることで、直接ダウンロードリンクとして利用できる。
https://drive.google.com/uc?export=download&id=xxxxxxxxxx
試しにブラウザでアクセスしてみると、自動的にダウンロードが始まるはず
ステップ4:Swift / Kotlin アプリでデータをfetchする(サンプルコード)
Swift の場合
let url = URL(string: "https://drive.google.com/uc?export=download&id=xxxxxxxxxx")!
URLSession.shared.dataTask(with: url) { data, _, _ in
if let data = data,
let decoded = try? JSONDecoder().decode([Location].self, from: data) {
DispatchQueue.main.async {
self.locations = decoded
}
}
}.resume()
Location構造体は JSON の形式に合わせて定義する
Kotlin の場合
val jsonText = withContext(Dispatchers.IO) {
try {
URL("https://drive.google.com/uc?export=download&id=xxxxxxxxxx").readText()
} catch (e: Exception) {
Log.e("FetchError", "Failed to fetch JSON", e)
""
}
}
if (jsonText.isNotEmpty()) {
locations = Json.decodeFromString(jsonText)
}
.readText()だけでfetchできるKotlin、素晴らしい
注意点
Google Drive 上のファイルを削除して同じ名前のファイルを再アップロードしても、ファイル ID は変わってしまうため、URLが無効になってしまう。ファイルの内容を更新したい場合は、Drive 上で直接編集するか、既存のファイル ID を保持したまま上書きする必要がある。
私の場合は、Google Apps Script(GAS)を使って特定のファイル ID に対して自動的に書き込みを行うことで、リンクを変えずにデータを定期更新している。
また、Web アプリから fetch 関数でこのリンクにアクセスしようとしたところ、うまく動作しなかった。Webでは素直にGoogle Drive API、もしくは他のサービスを使うのが良さそう。
おわりに
今回紹介した「共有リンク方式」は静的コンテンツの配信に限られるが、APIキーの設定等も不要で、非常に手軽にファイルサーバーを構築できる方法だと感じる。私は選択肢の1つとして今後も活用していくと思う。
Discussion