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;
@endGodotBridge.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 プラグインを認識・読み込ませるための設定ファイルとなる。
- プラグイン名.gdipGodotに従いスネークケースで名前をつけた
- 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-stableBase.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=arm64Debug.xcconfig にファイルの指定
// リンクする静的ライブラリを明示(拡張子不要)
// ここに書かない場合には Link Binary With Libraries に追加する必要がある
OTHER_LDFLAGS = \
  $(inherited) \
  -lgodot.ios.template_debug.arm64Release.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を使いたい

 
  