Godot-iOSキーボードの高さの変化を通知するネイティブプラグインを作る-失敗
前置き
このノートは失敗編。
成功したらちゃんとしたノートを書く
背景
Godotにはキーボードの高さを取得する関数はあるが、キーボードの高さの変化を取得する方法がないため、GodotでiOSのキーボードに追従するツールバーを実装するためにはiOSプラグインの実装が必要だった。
環境
- Godot 4.4.stable
- Xcode 16.2
公式ドキュメント
目標
iOS では UIKeyboardWillChangeFrameNotificationでキーボードの高さの変化を監視することができる。 なのでGodot上でこの値を監視できるようなiOSプラグインを作る。
ちなみにiOSネイティブアプリではUIKeyboardLayoutGuideという便利なものがiOS15より使えるようになっているよ。
実装
iOS 側
.xcframework
を作る。
- 新規 Xcode プロジェクト →
Framework
(iOS) - Product Name:
GodotKeyboardPlugin
- 言語: Swift
Scripts
フォルダを作成してその中にスクリプトを置くようにした。DocC はドキュメント用なのでその中のResources
には置かないようにする。
KeyboardObserver.swift
GodotBridge.h
GodotBridge.mm
KeyboardObserver.swift
import UIKit
@objcMembers
public class KeyboardObserver: NSObject {
public class var shared: KeyboardObserver {
struct Static {
static let instance: KeyboardObserver = KeyboardObserver()
}
return Static.instance
}
public var currentKeyboardHeight: Float = 0
override init() {
super.init()
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillChangeFrame(_:)),
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil
)
}
func keyboardWillChangeFrame(_ notification: Notification) {
guard let userInfo = notification.userInfo,
let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
return
}
let screenHeight = UIScreen.main.bounds.height
let keyboardHeight = Float(screenHeight - keyboardFrame.origin.y)
currentKeyboardHeight = max(keyboardHeight, 0)
}
}
GodotBridge.h
#import <Foundation/Foundation.h>
@interface GodotBridge : NSObject
+ (void)initializePlugin;
+ (float)getKeyboardHeight;
@end
GodotBridge.mm
#import "GodotBridge.h"
#import "GodotKeyboardPlugin-Swift.h"
@implementation GodotBridge
+ (void)initializePlugin {
// [KeyboardObserver shared]; // 初期化して監視開始
}
+ (float)getKeyboardHeight {
return [KeyboardObserver shared].currentKeyboardHeight;
}
@end
// Godot が呼び出すプラグイン初期化関数
// この関数名を `.gdip` に書く必要がある
extern "C" void godot_ios_plugin_init() {
[GodotBridge initializePlugin];
}
XCFramework
をビルドする
generate_xcframework.sh
を用意する
#!/bin/bash
set -e
### === 設定 ===
SCHEME="GodotKeyboardPlugin"
OUTPUT_NAME="GodotKeyboardPlugin"
ARCHIVE_DIR="./build"
OUTPUT_DIR="./output"
# 出力ファイル名
RELEASE_XC="$OUTPUT_DIR/${OUTPUT_NAME}.release.xcframework"
DEBUG_XC="$OUTPUT_DIR/${OUTPUT_NAME}.debug.xcframework"
# .framework 内の実体バイナリの仮名
FRAMEWORK_BINARY_NAME="$OUTPUT_NAME" # 通常 .framework の中身と一致
### ============
if [[ -z "$ARCHIVE_DIR" || "$ARCHIVE_DIR" == "/" || "$ARCHIVE_DIR" == "." || "$ARCHIVE_DIR" == ".." ]]; then
echo "❌ ARCHIVE_DIR が不正です → '$ARCHIVE_DIR'"
exit 1
fi
if [[ -d "$ARCHIVE_DIR" ]]; then
echo "アーカイブディレクトリ '$ARCHIVE_DIR' を削除します..."
rm -rf "$ARCHIVE_DIR"
fi
if [[ -d "$OUTPUT_DIR" ]]; then
echo "出力ディレクトリ '$OUTPUT_DIR' を削除します..."
rm -rf "$OUTPUT_DIR"
fi
mkdir -p "$ARCHIVE_DIR" "$OUTPUT_DIR"
echo "📦 Archiving RELEASE (device/simulator)..."
# Archive: Release - iOS
xcodebuild archive \
-scheme "$SCHEME" \
-configuration Release \
-destination "generic/platform=iOS" \
-archivePath "$ARCHIVE_DIR/${SCHEME}-iOS-Release.xcarchive" \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# Archive: Release - Simulator
xcodebuild archive \
-scheme "$SCHEME" \
-configuration Release \
-destination "generic/platform=iOS Simulator" \
-archivePath "$ARCHIVE_DIR/${SCHEME}-Sim-Release.xcarchive" \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# 抽出関数
extract_a_from_framework() {
archive_path=$1
platform_name=$2
out_dir=$3
framework_path="$archive_path/Products/Library/Frameworks/${SCHEME}.framework"
binary_path="$framework_path/$FRAMEWORK_BINARY_NAME"
headers_path="$framework_path/Headers"
cp "$binary_path" "$out_dir/lib${SCHEME}.a"
cp -R "$headers_path" "$out_dir/include"
}
# 抽出先
RELEASE_IOS_DIR="$ARCHIVE_DIR/extracted-ios-release"
RELEASE_SIM_DIR="$ARCHIVE_DIR/extracted-sim-release"
mkdir -p "$RELEASE_IOS_DIR" "$RELEASE_SIM_DIR"
extract_a_from_framework "$ARCHIVE_DIR/${SCHEME}-iOS-Release.xcarchive" "ios" "$RELEASE_IOS_DIR"
extract_a_from_framework "$ARCHIVE_DIR/${SCHEME}-Sim-Release.xcarchive" "sim" "$RELEASE_SIM_DIR"
# Create XCFramework (RELEASE)
xcodebuild -create-xcframework \
-library "$RELEASE_IOS_DIR/lib${SCHEME}.a" \
-headers "$RELEASE_IOS_DIR/include" \
-library "$RELEASE_SIM_DIR/lib${SCHEME}.a" \
-headers "$RELEASE_SIM_DIR/include" \
-output "$RELEASE_XC"
echo "✅ RELEASE xcframework created: $RELEASE_XC"
### === DEBUG ===
echo "📦 Archiving DEBUG (device/simulator)..."
# Archive: Debug - iOS
xcodebuild archive \
-scheme "$SCHEME" \
-configuration Debug \
-destination "generic/platform=iOS" \
-archivePath "$ARCHIVE_DIR/${SCHEME}-iOS-Debug.xcarchive" \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# Archive: Debug - Simulator
xcodebuild archive \
-scheme "$SCHEME" \
-configuration Debug \
-destination "generic/platform=iOS Simulator" \
-archivePath "$ARCHIVE_DIR/${SCHEME}-Sim-Debug.xcarchive" \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# 抽出先
DEBUG_IOS_DIR="$ARCHIVE_DIR/extracted-ios-debug"
DEBUG_SIM_DIR="$ARCHIVE_DIR/extracted-sim-debug"
mkdir -p "$DEBUG_IOS_DIR" "$DEBUG_SIM_DIR"
extract_a_from_framework "$ARCHIVE_DIR/${SCHEME}-iOS-Debug.xcarchive" "ios" "$DEBUG_IOS_DIR"
extract_a_from_framework "$ARCHIVE_DIR/${SCHEME}-Sim-Debug.xcarchive" "sim" "$DEBUG_SIM_DIR"
# Create XCFramework (DEBUG)
xcodebuild -create-xcframework \
-library "$DEBUG_IOS_DIR/lib${SCHEME}.a" \
-headers "$DEBUG_IOS_DIR/include" \
-library "$DEBUG_SIM_DIR/lib${SCHEME}.a" \
-headers "$DEBUG_SIM_DIR/include" \
-output "$DEBUG_XC"
echo "✅ DEBUG xcframework created: $DEBUG_XC"
ターミナルから実行する
sh generate_xcframework.sh
GodotKeyboardPlugin.xcframework
が作られればおk。
このとき GodotKeyboardPlugin.xcframework
の内部に .framework
になっている場合はGodot上で読み込みができないので注意。
# 失敗!
├── GodotKeyboardPlugin.debug.xcframework
│ ├── Info.plist
│ ├── ios-arm64
│ │ └── GodotKeyboardPlugin.framework # これは認識できない
│ └── ios-arm64_x86_64-simulator
│ └── GodotKeyboardPlugin.framework # これは認識できない
.a
ファイルが入っていれば成功。
# ok!
├── GodotKeyboardPlugin.debug.xcframework
│ ├── Info.plist
│ ├── ios-arm64
│ │ ├── Headers
│ │ └── libGodotKeyboardPlugin.a
│ └── ios-arm64_x86_64-simulator
│ ├── Headers
│ └── libGodotKeyboardPlugin.a
└── GodotKeyboardPlugin.release.xcframework
├── Info.plist
├── ios-arm64
│ ├── Headers
│ └── libGodotKeyboardPlugin.a
└── ios-arm64_x86_64-simulator
├── Headers
└── libGodotKeyboardPlugin.a
フォルダの中身
GodotKeyboardPlugin
のフォルダの中は次の通りになった。
.
├── build
│ ├── GodotKeyboardPlugin-iOS.xcarchive
│ └── GodotKeyboardPlugin-Simulator.xcarchive
├── generate_xcframework.sh
├── GodotKeyboardPlugin
│ ├── GodotKeyboardPlugin.docc
│ ├── GodotKeyboardPlugin.h
│ └── Scripts
├── GodotKeyboardPlugin.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ └── xcuserdata
└── xcframework
└── GodotKeyboardPlugin.xcframework
.gdip
ファイルを作る
Godotと紐づけるために godot_keyboard_plugin.gdip
ファイルを作る。
このファイルは Godot プラグインを認識・読み込ませるための設定ファイルとなる。
プラグイン名.gdip
Godotに従いスネークケースで名前をつけた- Creating an iOS plugin - Godot Docsの6ステップ目に書き方の参考がある
- godot-ios-pluginでの書き方も参考になる
[config]
name = "GodotKeyboardPlugin"
binary = "GodotKeyboardPlugin.xcframework"
initialization = "godot_ios_plugin_init"
[dependencies]
linked = []
embedded = []
system = ["UIKit.framework", "Foundation.framework"]
[linker_flags]
linker_flags = ["-ObjC"]
セクション | キー | 内容 |
---|---|---|
[config] |
name |
プラグインの表示名 |
binary |
.xcframework のファイル名 |
|
initialization |
Godot が呼び出す C 関数名(Objective-C 側で extern "C" された godot_ios_plugin_init() ) |
|
[dependencies] |
system |
使用している Apple のフレームワーク。Swift/Obj-C で UIKit / Foundation を使用しているため記載 |
[linker_flags] |
-ObjC |
Objective-C カテゴリやメソッドを強制リンクするため(Swift → Obj-C ブリッジのために必要) |
Godot 側
GodotKeyboardPlugin.xcframework
とGodotKeyboardPlugin.gdip
を配置する。
res://ios/plugins/GodotKeyboardPlugin/
├── GodotKeyboardPlugin.gdip
├── GodotKeyboardPlugin.xcframework
だめ!!!!!!でした
ERROR: Invalid plugin config file godot_keyboard_plugin/godot_keyboard_plugin.gdip
【Godot】ATTダイアログを表示するプラグインを作る | コドモとアプリ
考える
- SConsを使ったほうが良さそう?
- Godot本体が必要?
- Godot-iOSキーボードの高さの変化を通知するネイティブプラグインを作る に新しくきれいに書く
必要なこと
- Xcodeプロジェクトを作成する
- Static Library
- iOS DevelopmentTarget の設定
- TARGET > Build Settings > Header Search Paths
- Godot 本体の
godot/platform/ios
を設定する
- Godot 本体の
.gdip
を作る- SConsを使ってGodotエンジン本体のiOSヘッダーを抽出する
- これは Godot.app からは取得できないので、godotengine/godot - GithHubから取得
bin
フォルダを作るSContruct
ファイルから.a
を作る
https://github.com/godotengine/godot/tree/master/platform/ios この中身が必要ってことよね これが SwiftPackage 的な感じになってればいいのになー
- Compiling for iOS
- Godot エンジンのヘッダファイルをライブラリの依存関係として追加
- かいてあるじゃん!
- naithar/godot_ios_plugin
- これ用の
.xcconfig
はよさそう.xcconfig
は static library だとうまく動かなさそう- framework にする?
- でもやっぱり framework からは無理そう
- framework にする?
- これ用の
Xcode.app
のエイリアスを貼っておく。(実際にはXcode16.2.appが使われる)
sudo ln -s /Applications/Xcode16.2.app /Applications/Xcode.app
シンボル一覧の確認
nm -gU build/extracted_static_libs/GodotKeyboardPlugin_ios-arm64.a
0000000000004ee8 T _$s19GodotKeyboardPlugin0B8ObserverC07currentB6HeightSfvMTj
0000000000005fc4 S _$s19GodotKeyboardPlugin0B8ObserverC07currentB6HeightSfvMTq
0000000000004e90 T _$s19GodotKeyboardPlugin0B8ObserverC07currentB6HeightSfvgTj
0000000000005fb4 S _$s19GodotKeyboardPlugin0B8ObserverC07currentB6HeightSfvgTq
0000000000008168 S _$s19GodotKeyboardPlugin0B8ObserverC07currentB6HeightSfvpMV
0000000000004ebc T _$s19GodotKeyboardPlugin0B8ObserverC07currentB6HeightSfvsTj
0000000000005fbc S _$s19GodotKeyboardPlugin0B8ObserverC07currentB6HeightSfvsTq
0000000000004f14 T _$s19GodotKeyboardPlugin0B8ObserverC23keyboardWillChangeFrameyy10Foundation12NotificationVFTj
0000000000005fcc S _$s19GodotKeyboardPlugin0B8ObserverC23keyboardWillChangeFrameyy10Foundation12NotificationVFTq
0000000000004e78 T _$s19GodotKeyboardPlugin0B8ObserverC6sharedACvgZTj
0000000000005fac S _$s19GodotKeyboardPlugin0B8ObserverC6sharedACvgZTq
0000000000004440 T _$s19GodotKeyboardPlugin0B8ObserverCACycfC
0000000000004464 T _$s19GodotKeyboardPlugin0B8ObserverCACycfc
0000000000004be8 T _$s19GodotKeyboardPlugin0B8ObserverCMa
0000000000005f78 S _$s19GodotKeyboardPlugin0B8ObserverCMn
0000000000005cf8 S _$s19GodotKeyboardPlugin0B8ObserverCMo
0000000000004e5c T _$s19GodotKeyboardPlugin0B8ObserverCMu
000000000000c240 S _$s19GodotKeyboardPlugin0B8ObserverCN
0000000000004b70 T _$s19GodotKeyboardPlugin0B8ObserverCfD
0000000000005cb0 S _GodotKeyboardPluginVersionNumber
0000000000005c70 S _GodotKeyboardPluginVersionString
000000000000c1b8 S _OBJC_CLASS_$_GodotBridge
000000000000c240 S _OBJC_CLASS_$__TtC19GodotKeyboardPlugin16KeyboardObserver
000000000000c190 S _OBJC_METACLASS_$_GodotBridge
000000000000c2c8 D _OBJC_METACLASS_$__TtC19GodotKeyboardPlugin16KeyboardObserver
00000000000040b0 T _godot_ios_plugin_init
- 調査した感じ
libgodot.ios.a
を使ってGodot 側のライブラリをiOSのプラグイン側に導入しないといけない。
これをGodot と iOS で紐づけるために libgodot.ios.a
が必要になる。
extern "C" void godot_ios_plugin_init() {
[GodotBridge initializePlugin];
}
そのために Godot本体から SConsを使ってそのライブラリを導入する必要がある。
# 重いからなるべく軽量にクローンする
git clone --depth=1 --branch 4.4-stable --single-branch https://github.com/godotengine/godot.git
scons platform=ios target=template_debug arch=arm64
もしかして .xcframework
がここで入手できるなら、その .xcframework
をXcodeにぶちこんでどうにかならんかね?
misc/dist/ios_xcode
の中を見る- おお これ使ってできるんでない?
godot_ios.xcodeproj
は壊れている- これは関係ないみたい
bin
の中にlibgodot.ios.template_debug.arm64.a
があった!- やっぱり GitHub サブモジュールとするのがいいのかね
サブモジュールでやる
ちゃんと公式に合わせた形でやるしかない。
ヘッダーファイルの抽出は大変なのでサブモジュールとしておいて、そこから HEADER_SEARCH_PATH
に設定するほうが確実。
直接 git submodule add
を使うと重たいので shallow clone を使う。
cd GodotPlugin/GodotKeyboardPlugin
// サブモジュール化したいリポジトリを取得
git clone --depth=1 --branch 4.4.1-stable https://github.com/godotengine/godot.git godot
// .gitmodules を追加
touch .gitmodules
// 書いた後に submodule init をしてサブモジュールとして認識させる (.git/configファイルに追加される)
git submodule init
// サブモジュールのアップデートが必要なとき
git submodule update --init --recursive --recommend-shallow --depth 1
.gitmodules
[submodule "godot"]
path = godot
url = https://github.com/godotengine/godot.git
shallow = true
branch = 4.4.1-stable
Base.xcconfig
に追加
HEADER_SEARCH_PATHS = \
$(SRCROOT)/godot \
$(SRCROOT)/godot/core \
$(SRCROOT)/godot/core/os \
$(SRCROOT)/godot/scene \
$(SRCROOT)/godot/platform \
$(SRCROOT)/godot/platform/iphone \
$(SRCROOT)/godot/main \
$(SRCROOT)/godot/servers \
$(SRCROOT)/godot/modules \
$(SRCROOT)/godot/drivers \
$(SRCROOT)/godot/thirdparty
# godot フォルダに移動
cd GodotPlugin/GodotKeyboardPlugin/godot
# scons を実行する
# これで libgodot.ios.template_debug.arm64.a を得ることができる
scons platform=ios target=template_debug arch=arm64
# リリース用も作っておく
scons platform=ios target=template_release arch=arm64
Debug.xcconfig
にファイルの指定
// リンクする静的ライブラリを明示(拡張子不要)
// ここに書かない場合には Link Binary With Libraries に追加する必要がある
OTHER_LDFLAGS = \
$(inherited) \
-lgodot.ios.template_debug.arm64
Release.xcconfig
にファイルの指定
// リンクする静的ライブラリを明示(拡張子不要)
OTHER_LDFLAGS = \
$(inherited) \
-lgodot.ios.template_release.arm64
もし OTHER_LDFLAGS
をかかない場合には lgodot.ios.template_debug.arm64.a
ファイルを LInk Binary With Libraries に登録しておく必要がある。(書いた場合は不要)
xcodebuild -create-xcframework \
-library ./build/Release-iphoneos/GodotKeyboardPlugin.a \
-headers ./include \
-library ./build/Release-iphonesimulator/GodotKeyboardPlugin.a \
-headers ./include \
-output GodotKeyboardPlugin.xcframework
"Could not build module Foundation" error when compiling for iOS with SDK 15.2 #56092
あかん。
とりあえずまずは objcでかいて、それがGodotで動くことを確認してからSwiftにしよう。 -> これももううまくいかぬ...どうして
- zt-pawer/SwiftGodotIosPlugins
- これためす
- SwiftGodot を使っているね
- Swift 側にそれを使うんだ
- Package.swift もある
build.sh
実行してみた- 失敗したのでGPTに書き直してもらった
- エラー出て
GameCenter.framework
ができていない- SwiftPackage を Xcode で開いてみるとエラーが出ている
Trust & Enable
を実行しないとダメかも- したけどだめ
iOS
をターゲットにしてArchive
したらGameCenter.framework
をゲットしたMac
もターゲットにしてやってみる
res://addons/iosplugins/gamecenter.gdextension
res://addons/iosplugins/ios
の中にGameCenter.framework
とSwiftGodot.framework
をいれる- mac 版も入れないとだめ
- これは framework だとダメ
swift build --configuration release --product GameCenter --build-path .build-macos
を実行すると.build-macos/arm64-apple-macosx/release/
に書き出された!
gamecenter.gdextension
の中身
[configuration]
entry_symbol = "gamecenter"
compatibility_minimum = 4.2
relodable = true
[libraries]
macos.debug = "res://addons/iosplugins/macos/libGameCenter.dylib"
macos.release = "res://addons/iosplugins/macos/libGameCenter.dylib"
ios.debug = "res://addons/iosplugins/ios/GameCenter.framework"
ios.release = "res://addons/iosplugins/ios/GameCenter.framework"
[dependencies]
macos.debug = {"res://addons/iosplugins/macos/libSwiftGodot.dylib" : ""}
macos.release = {"res://addons/iosplugins/macos/libSwiftGodot.dylib" : ""}
ios.debug = {"res://addons/iosplugins/ios/SwiftGodot.framework" : ""}
ios.release = {"res://addons/iosplugins/ios/SwiftGodot.framework" : ""}
それでこれ
.
├── addons
│ └── iosplugins
│ ├── gamecenter.gdextension
│ ├── gamecenter.gdextension.uid
│ ├── ios
│ │ ├── GameCenter.framework
│ │ └── SwiftGodot.framework
│ └── macos
│ ├── libGameCenter.dylib
│ └── libSwiftGodot.dylib
これで無事にGodot上では動いていた!!!!!!
正攻法かわからんが、とりあえずSwiftGodot + SwiftPackage + GDExtensionでできた。 ビルドがイマイチうまくいっていないので、うまくいったらまとめる
-> Godot-iOSキーボードの高さの変化を通知するネイティブプラグインを作る
SwiftGodotを使ってやってみるぞ!!
.gdextension
- Swift Package Manager でやるぞい
プラグイン.framework
SwiftGodot.framework
関連ノート
- Godotでモバイル端末のキーボードの高さの取得する
- GodotでiOSのキーボードに追従するツールバーを実装する
- GodotでiOS用プラグインのgodot-ios-pluginsを使いたい
