Build PhasesのRunScriptでJsonをVaridateする
ローカルフォルダ内に存在するJsonが破損している場合起動時のクラッシュではなく、そもそもビルドを失敗させたいと思い、RunScriptでSwiftを使ってVaridate試してみました。
.shファイルの追加
Run Scriptの導入はいろんな方が記事を書いてくれていますが、私はXCodeのRun Scriptを試しに触ってみるという記事を参考に入れました。本記事ではRunScriptの作成までの過程は飛ばします。
RunScriptに用意されているエディタは小さいのでScriptファイルを作成しそのファイルに記述を行います。
File > New > File > Other > Shell Script
Run Scriptとのパスを通す
作成したShell ScriptファイルをRunScriptで動かすためにPathを通します。
私の場合はプロジェクト直下にScriptファイルを作成したので下記のようになりました。
./Script.sh
パスが通っているかの確認
作成したShellScriptの中身を下記のように書き換えてビルドしhelloと出力されていれば成功です!
#!/bin/sh
echo "hello"
Shell ScriptでSwiftを使う
Swiftの呼び出し
ここからが本題です。以下のようなコマンドでShell ScriptからSwiftを使用することができます。
echo "print(\" Hello Swift!!!\ ")" | swift
これだと1行だけしか使えないため下記のように記述することでswift_code()内のブロックでSwiftを使えるようになります。
#!/bin/bash
swift_code() {
cat<<EOF
print("Hello Swift!!!")
EOF
}
echo "$(swift_code)" | swift -
フレームワークを使う
echoの部分に下記のように書き換えることでフレームワークを使うことができるようになります。試していませんがCarthageでいれたライブラリも使えるみたいです。
echo "$(swift_code)" | DEVELOPER_DIR = "$ DEVELOPER_DIR" xcrun --sdk macosx "$ TOOLCHAIN_DIR / usr / bin /" swift -F "$ SRCROOT / Carthage / Build / Mac /" -
Jsonのparseを行うRun Script
はじめにBundleを使ってPathを取得しようとしていたのですが全然取れずにハマっていましたが、FileManagerを使ったらすんなり取れました。
#!/bin/sh
swift_code() {
cat<<EOF
import Foundation
struct Test: Codable {
var message: String
}
let fileManager = FileManager.default
let path = fileManager.currentDirectoryPath
print(path)
let content = try String(contentsOfFile: "\(path)/RunScriptTest/hoge.json")
let data = try JSONDecoder().decode(Test.self, from: content.data(using: .utf8)!)
print(data.message)
EOF
}
# Run the Swift code in swift_code()
echo "$(swift_code)" \
| DEVELOPER_DIR="$DEVELOPER_DIR" \
xcrun --sdk macosx \
"$TOOLCHAIN_DIR/usr/bin/"swift -F "$SRCROOT/Carthage/Build/Mac/" -
プロジェクト内のSwiftファイルを使う
上記のコードでvaridateをすることは可能ですが、Json構造が変更された際RunScriptも修正が必要になってしまう為、既存のSwiftファイルを使用するのがベストだと思います。
また、Varidateを行っている部分も別ファイルに移植してすっきりさせました。
修正後のRunScript
#!/bin/sh
swift_code() {
PARSE_STRUCT=./RunScriptTest/Parse.swift
VARIDATE_JSON=./VaridateJson.swift
cat ${PARSE_STRUCT} ${VARIDATE_JSON}
}
# Run the Swift code in swift_code()
echo "$(swift_code)" \
| DEVELOPER_DIR="$DEVELOPER_DIR" \
xcrun --sdk macosx \
"$TOOLCHAIN_DIR/usr/bin/"swift -F "$SRCROOT/Carthage/Build/Mac/" -
Parse用の構造体
ScriptのPARSE_STRUCT=./RunScriptTest/Parse.swiftでパスを取得していた部分のコードです
struct Parse: Codable {
var message: String
}
Varidateを行う部分のコード
ScriptのVARIDATE_JSON=./VaridateJson.swiftでパスを取得している部分のコードです。
SwiftのコードなのでSwiftファイルで作成したのですが、Swiftファイルは記述をすると勝手にビルドが走ってしまいエラーが出てしまう為、そのままではコンパイラがFileManagerなどがわからずエラーになってしまいます。
import Foundation
let fileManager = FileManager.default
let path = fileManager.currentDirectoryPath
print(path)
let content = try String(contentsOfFile: "\(path)/RunScriptTest/hoge.json")
let data = try JSONDecoder().decode(Parse.self, from: content.data(using: .utf8)!)
print(data.message)
正しい対応かはわかりませんが、右端のタブのIdentity and Type > Typeの項目をSwiftからShell Scriptにすることでエラーが出なくなります。
初めから拡張子をShell Scriptのものにして作成すればいい話なのですが、Xcodeのファイルツリー構造を眺めた際、Swiftで記述がされているのにSwiftファイルじゃないと気持ち悪いと感じたのでこのような対応をしました。
Xcodeのファイル構造
遭遇したエラー
本番環境でRunScriptを導入した際ScriptName.sh: Permission deniedというエラーが発生しました。
調べてみるとこのエラーはファイル権限によるものらしく
Unity開発:XCodeでビルド出来ないという記事が参考になりました。