From a8457d26782fcacaea349b9689c834a6cdc37adb Mon Sep 17 00:00:00 2001 From: Gustavo Maciel Date: Sat, 21 Mar 2026 15:43:01 -0300 Subject: [PATCH 1/6] refactor: update to Godot 4.7 and migrate iOS to structured SPM format --- platforms/godot_editor/addons/admob/admob.gd | 3 - .../internal/exporters/ios/export_plugin.gd | 166 ------------------ .../exporters/ios/export_plugin.gd.uid | 1 - .../admob/internal/services/export_service.gd | 55 ------ .../internal/services/export_service.gd.uid | 1 - .../internal/services/pbxproj_service.gd | 70 -------- .../internal/services/pbxproj_service.gd.uid | 1 - .../godot_editor/addons/admob/plugin.cfg | 2 +- platforms/godot_editor/project.godot | 2 +- platforms/ios/Package.swift | 130 +++++++------- platforms/ios/src/ads/config/package.gd | 2 +- .../src/ads/config/poing-godot-admob-ads.gdip | 9 +- .../meta/config/poing-godot-admob-meta.gdip | 8 +- .../config/poing-godot-admob-vungle.gdip | 8 +- 14 files changed, 90 insertions(+), 368 deletions(-) delete mode 100644 platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd delete mode 100644 platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd.uid delete mode 100644 platforms/godot_editor/addons/admob/internal/services/export_service.gd delete mode 100644 platforms/godot_editor/addons/admob/internal/services/export_service.gd.uid delete mode 100644 platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd delete mode 100644 platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd.uid diff --git a/platforms/godot_editor/addons/admob/admob.gd b/platforms/godot_editor/addons/admob/admob.gd index ebcfd766a..db821c899 100644 --- a/platforms/godot_editor/addons/admob/admob.gd +++ b/platforms/godot_editor/addons/admob/admob.gd @@ -29,17 +29,14 @@ const CSharpService := preload("res://addons/admob/internal/services/csharp_serv var _main_exporter := preload("res://addons/admob/internal/exporters/main_export_plugin.gd").new() var _android_exporter := preload("res://addons/admob/internal/exporters/android/export_plugin.gd").new() -var _ios_exporter := preload("res://addons/admob/internal/exporters/ios/export_plugin.gd").new() func _enter_tree() -> void: CSharpService.manage_visibility(self) add_export_plugin(_main_exporter) add_export_plugin(_android_exporter) - add_export_plugin(_ios_exporter) add_tool_submenu_item(MENU_NAME, AdMobEditorMenu.new(self)) func _exit_tree() -> void: remove_export_plugin(_main_exporter) remove_export_plugin(_android_exporter) - remove_export_plugin(_ios_exporter) remove_tool_menu_item(MENU_NAME) diff --git a/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd b/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd deleted file mode 100644 index 2676df452..000000000 --- a/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd +++ /dev/null @@ -1,166 +0,0 @@ -# MIT License - -# Copyright (c) 2026-present Poing Studios - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -extends EditorExportPlugin - -const ExportService := preload("res://addons/admob/internal/services/export_service.gd") -const PbxprojService := preload("res://addons/admob/internal/services/pbxproj_service.gd") -const PLUGIN_CONFIG_DIR := "res://ios/plugins/" - -var _export_path: String = "" -var _spm_dependencies: Array[Dictionary] = [] - -func _get_name() -> String: - return "PoingAdMobIOS" - -func _supports_platform(platform: EditorExportPlatform) -> bool: - return platform.get_os_name() == "iOS" - -func _export_begin(features: PackedStringArray, is_debug: bool, path: String, flags: int) -> void: - _export_path = path - -func _export_end() -> void: - if _export_path.is_empty(): - return - - var activated_plugins := ExportService.get_activated_plugins("iOS") - if activated_plugins.is_empty(): - return - - _spm_dependencies = _collect_spm_dependencies(activated_plugins) - if _spm_dependencies.is_empty(): - return - - var export_dir := _export_path.get_base_dir() - _generate_package_swift(export_dir, _spm_dependencies) - _generate_dummy_source(export_dir) - - # The .xcodeproj is generated by Godot AFTER _export_end completes - # (it's created during Xcode project template extraction, which happens - # after save_pack finishes). We must defer the pbxproj patching. - _defer_pbxproj_patch.call_deferred(export_dir) - -func _defer_pbxproj_patch(export_dir: String) -> void: - _patch_xcodeproj(export_dir) - _spm_dependencies.clear() - -func _patch_xcodeproj(export_dir: String) -> void: - var project_name := _export_path.get_file().get_basename() - var pbxproj_path := export_dir.path_join(project_name + ".xcodeproj/project.pbxproj") - - if FileAccess.file_exists(pbxproj_path): - PbxprojService.patch(pbxproj_path) - return - - var dir := DirAccess.open(export_dir) - if not dir: - push_warning("AdMob: Could not open export directory: %s" % export_dir) - return - - dir.list_dir_begin() - var file_name := dir.get_next() - while file_name != "": - if file_name.ends_with(".xcodeproj"): - var found_path := export_dir.path_join(file_name).path_join("project.pbxproj") - if FileAccess.file_exists(found_path): - PbxprojService.patch(found_path) - else: - push_warning("AdMob: project.pbxproj not found at: %s" % found_path) - break - file_name = dir.get_next() - -func _collect_spm_dependencies(activated_plugins: Array[String]) -> Array[Dictionary]: - var deps: Array[Dictionary] = [] - var dir := DirAccess.open(PLUGIN_CONFIG_DIR) - if not dir: - return deps - - dir.list_dir_begin() - var file_name := dir.get_next() - while file_name != "": - if not dir.current_is_dir() and file_name.ends_with(".gdip"): - var config := ConfigFile.new() - var err := config.load(PLUGIN_CONFIG_DIR.path_join(file_name)) - if err == OK: - var plugin_name := config.get_value("config", "name", "") - if activated_plugins.has(plugin_name): - if config.has_section_key("dependencies", "admob_packages"): - var packages: Array = config.get_value("dependencies", "admob_packages", []) - for pkg_str: String in packages: - # url@mode:version|product - var main_parts := pkg_str.split("|") - var product := main_parts[1] if main_parts.size() > 1 else "" - - var url_and_rules := main_parts[0].split("@") - var url := url_and_rules[0] - - if url_and_rules.size() > 1: - var rules := url_and_rules[1].split(":") - if rules.size() > 1: - var dep := { - "url": url, - "version": rules[1], - "kind": rules[0], - "product": product - } - deps.append(dep) - file_name = dir.get_next() - return deps - -func _generate_package_swift(export_dir: String, dependencies: Array[Dictionary]) -> void: - var package_deps_str := "" - var target_deps_str := "" - var processed_urls := [] - var processed_products := [] - - for dep in dependencies: - var url: String = dep.url - var product: String = dep.product - var package_name: String = url.get_file().trim_suffix(".git") - - if not processed_urls.has(url): - processed_urls.append(url) - var version_rule := 'exact: "%s"' % dep.version if dep.kind == "exact" else 'from: "%s"' % dep.version - package_deps_str += ' .package(url: "%s", %s),\n' % [url, version_rule] - - if not processed_products.has(product): - processed_products.append(product) - target_deps_str += ' .product(name: "%s", package: "%s"),\n' % [product, package_name] - - var content := "// swift-tools-version:5.9\nimport PackageDescription\n\nlet package = Package(\n name: \"PoingGodotAdMobDeps\",\n platforms: [.iOS(.v13)],\n products: [\n .library(\n name: \"PoingGodotAdMobDeps\",\n targets: [\"PoingGodotAdMobDeps\"]),\n ],\n dependencies: [\n" + package_deps_str + " ],\n targets: [\n .target(\n name: \"PoingGodotAdMobDeps\",\n dependencies: [\n" + target_deps_str + " ],\n path: \"PoingGodotAdMobDeps\"\n )\n ]\n)\n" - - var file := FileAccess.open(export_dir.path_join("Package.swift"), FileAccess.WRITE) - if file: - file.store_string(content) - file.close() - print("AdMob: Generated Package.swift at %s" % export_dir) - -func _generate_dummy_source(export_dir: String) -> void: - var source_dir := export_dir.path_join("PoingGodotAdMobDeps") - if not DirAccess.dir_exists_absolute(source_dir): - DirAccess.make_dir_recursive_absolute(source_dir) - - var content := "// Dummy\nimport Foundation\n\npublic struct PoingGodotAdMobDeps {\n public init() {}\n}\n" - var file := FileAccess.open(source_dir.path_join("Dummy.swift"), FileAccess.WRITE) - if file: - file.store_string(content) - file.close() diff --git a/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd.uid b/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd.uid deleted file mode 100644 index 30aa27d72..000000000 --- a/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c74oxvnajqsbq diff --git a/platforms/godot_editor/addons/admob/internal/services/export_service.gd b/platforms/godot_editor/addons/admob/internal/services/export_service.gd deleted file mode 100644 index dec886d82..000000000 --- a/platforms/godot_editor/addons/admob/internal/services/export_service.gd +++ /dev/null @@ -1,55 +0,0 @@ -# MIT License - -# Copyright (c) 2026-present Poing Studios - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -const EXPORT_PRESETS_PATH := "res://export_presets.cfg" - -static func get_activated_plugins(platform_name: String) -> Array[String]: - var activated_plugins: Array[String] = [] - - if not FileAccess.file_exists(EXPORT_PRESETS_PATH): - return activated_plugins - - var config := ConfigFile.new() - var err := config.load(EXPORT_PRESETS_PATH) - if err != OK: - return activated_plugins - - for section in config.get_sections(): - if not section.begins_with("preset."): - continue - - var platform = config.get_value(section, "platform", "") - if platform != platform_name: - continue - - # Check options for this preset - var options_section = section + ".options" - if config.has_section(options_section): - for key in config.get_section_keys(options_section): - if key.begins_with("plugins/"): - var is_enabled = config.get_value(options_section, key, false) - if is_enabled: - var plugin_name = key.trim_prefix("plugins/") - if not activated_plugins.has(plugin_name): - activated_plugins.append(plugin_name) - - return activated_plugins diff --git a/platforms/godot_editor/addons/admob/internal/services/export_service.gd.uid b/platforms/godot_editor/addons/admob/internal/services/export_service.gd.uid deleted file mode 100644 index c94f33b75..000000000 --- a/platforms/godot_editor/addons/admob/internal/services/export_service.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b40k2rt37l86o diff --git a/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd b/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd deleted file mode 100644 index f1ef1de2a..000000000 --- a/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd +++ /dev/null @@ -1,70 +0,0 @@ -# MIT License -# -# Copyright (c) 2026-present Poing Studios -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -static func patch(path: String) -> void: - var content := FileAccess.get_file_as_string(path) - if content.is_empty(): - return - - if content.contains("AD0000000000000000000001"): - return - - var local_ref_id := "AD0000000000000000000001" - var product_dep_id := "AD0000000000000000000002" - var build_file_id := "AD0000000000000000000003" - - if not content.contains("/* Begin XCLocalSwiftPackageReference section */"): - content = content.replace("/* End PBXGroup section */", "/* End PBXGroup section */\n\n/* Begin XCLocalSwiftPackageReference section */\n/* End XCLocalSwiftPackageReference section */") - - if not content.contains("/* Begin XCSwiftPackageProductDependency section */"): - content = content.replace("/* End XCLocalSwiftPackageReference section */", "/* End XCLocalSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n/* End XCSwiftPackageProductDependency section */") - - var local_ref_def := " " + local_ref_id + ' /* XCLocalSwiftPackageReference "." */ = {\n isa = XCLocalSwiftPackageReference;\n relativePath = ".";\n };\n' - content = content.replace("/* End XCLocalSwiftPackageReference section */", local_ref_def + "/* End XCLocalSwiftPackageReference section */") - - var product_dep_def := " " + product_dep_id + ' /* PoingGodotAdMobDeps */ = {\n isa = XCSwiftPackageProductDependency;\n package = ' + local_ref_id + ' /* XCLocalSwiftPackageReference "." */;\n productName = "PoingGodotAdMobDeps";\n };\n' - content = content.replace("/* End XCSwiftPackageProductDependency section */", product_dep_def + "/* End XCSwiftPackageProductDependency section */") - - var build_file_def := " " + build_file_id + ' /* PoingGodotAdMobDeps in Frameworks */ = {isa = PBXBuildFile; productRef = ' + product_dep_id + " /* PoingGodotAdMobDeps */; };\n" - content = content.replace("/* Begin PBXBuildFile section */", "/* Begin PBXBuildFile section */\n" + build_file_def) - - if content.contains("packageReferences = ("): - content = content.replace("packageReferences = (", "packageReferences = (\n " + local_ref_id + ' /* XCLocalSwiftPackageReference "." */,') - else: - content = content.replace("productRefGroup =", "packageReferences = (\n " + local_ref_id + ' /* XCLocalSwiftPackageReference "." */,\n );\n productRefGroup =') - - if content.contains("packageProductDependencies = ("): - content = content.replace("packageProductDependencies = (", "packageProductDependencies = (\n " + product_dep_id + " /* PoingGodotAdMobDeps */,") - else: - content = content.replace("buildRules = (", "packageProductDependencies = (\n " + product_dep_id + " /* PoingGodotAdMobDeps */,\n );\n buildRules = (") - - var framework_section_start := content.find("isa = PBXFrameworksBuildPhase;") - if framework_section_start != -1: - var files_start := content.find("files = (", framework_section_start) - if files_start != -1: - content = content.insert(files_start + 9, "\n " + build_file_id + " /* PoingGodotAdMobDeps in Frameworks */,") - - var file := FileAccess.open(path, FileAccess.WRITE) - if file: - file.store_string(content) - file.close() - print("AdMob: Patched project.pbxproj with SPM dependencies") diff --git a/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd.uid b/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd.uid deleted file mode 100644 index a4e2d78d8..000000000 --- a/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cnp62bnm8nvgn diff --git a/platforms/godot_editor/addons/admob/plugin.cfg b/platforms/godot_editor/addons/admob/plugin.cfg index 6818db487..48a939d69 100644 --- a/platforms/godot_editor/addons/admob/plugin.cfg +++ b/platforms/godot_editor/addons/admob/plugin.cfg @@ -3,5 +3,5 @@ name="AdMob" description="The AdMob Plugin for Android and iOS." author="Poing Studios" -version="v4.3.1" +version="v4.3.2-dev" script="admob.gd" diff --git a/platforms/godot_editor/project.godot b/platforms/godot_editor/project.godot index a3ff446a3..e0669247f 100644 --- a/platforms/godot_editor/project.godot +++ b/platforms/godot_editor/project.godot @@ -75,7 +75,7 @@ compatibility/default_parent_skeleton_in_mesh_instance_3d=true config/name="AdMobAddon" run/main_scene="res://addons/admob/gdscript/sample/Main.tscn" -config/features=PackedStringArray("4.6", "GL Compatibility") +config/features=PackedStringArray("4.7", "GL Compatibility") config/icon="res://addons/admob/assets/icon-1024.png" [display] diff --git a/platforms/ios/Package.swift b/platforms/ios/Package.swift index f3455e870..505376895 100644 --- a/platforms/ios/Package.swift +++ b/platforms/ios/Package.swift @@ -2,59 +2,71 @@ import PackageDescription import Foundation -struct DependencyInfo { +struct SPMPackageInfo { let url: String let version: String - let mode: String - let product: String + let products: [String] } -func parseGDIPFile(at path: String) -> [DependencyInfo] { +func parseGDIPFile(at path: String) -> [SPMPackageInfo] { let fileURL = URL(fileURLWithPath: path) guard let content = try? String(contentsOf: fileURL, encoding: .utf8) else { return [] } - - // Regex to find admob_packages array content - let pattern = #"admob_packages\s*=\s*\[\s*([\s\S]*?)\s*\]"# - guard let regex = try? NSRegularExpression(pattern: pattern) else { return [] } - - let range = NSRange(content.startIndex..., in: content) - guard let match = regex.firstMatch(in: content, options: [], range: range) else { return [] } - - let arrayContent = String(content[Range(match.range(at: 1), in: content)!]) - - // Parse each line in the array: "url@mode:version|product" - let lines = arrayContent.components(separatedBy: ",") - var dependencies: [DependencyInfo] = [] - - for line in lines { - let trimmedLine = line.trimmingCharacters(in: .whitespacesAndNewlines) - .trimmingCharacters(in: CharacterSet(charactersIn: "\"")) - - if trimmedLine.isEmpty { continue } - - // Split by @ and | - let mainParts = trimmedLine.components(separatedBy: "|") - let product = mainParts.count > 1 ? mainParts[1] : "" - - let urlAndRules = mainParts[0].components(separatedBy: "@") - let url = urlAndRules[0] - - if urlAndRules.count > 1 { - let rules = urlAndRules[1].components(separatedBy: ":") - if rules.count > 1 { - dependencies.append(DependencyInfo( - url: url, - version: rules[1], - mode: rules[0], - product: product - )) - } + + guard let spmStart = content.range(of: "spm_packages") else { return [] } + let afterSpm = String(content[spmStart.upperBound...]) + + let sectionPattern = #"\n\s*\[[a-zA-Z]"# + let nextSection: String + if let sectionRegex = try? NSRegularExpression(pattern: sectionPattern), + let sectionMatch = sectionRegex.firstMatch(in: afterSpm, range: NSRange(afterSpm.startIndex..., in: afterSpm)) { + nextSection = String(afterSpm[afterSpm.startIndex.. String { + let pattern = #""\#(key)"\s*:\s*"([^"]+)""# + guard let regex = try? NSRegularExpression(pattern: pattern) else { return "" } + let range = NSRange(text.startIndex..., in: text) + guard let match = regex.firstMatch(in: text, options: [], range: range) else { return "" } + return String(text[Range(match.range(at: 1), in: text)!]) +} + +func extractArray(from text: String, key: String) -> [String] { + let pattern = #""\#(key)"\s*:\s*\[([^\]]*)\]"# + guard let regex = try? NSRegularExpression(pattern: pattern) else { return [] } + let range = NSRange(text.startIndex..., in: text) + guard let match = regex.firstMatch(in: text, options: [], range: range) else { return [] } + + let arrayContent = String(text[Range(match.range(at: 1), in: text)!]) + return arrayContent.components(separatedBy: ",") + .map { $0.trimmingCharacters(in: .whitespacesAndNewlines).trimmingCharacters(in: CharacterSet(charactersIn: "\"")) } + .filter { !$0.isEmpty } } var packageDependencies: [Package.Dependency] = [] @@ -88,25 +100,21 @@ if gdipFiles.isEmpty { for gdipFile in gdipFiles { print("PoingAdMob: Parsing \(gdipFile)") - let deps = parseGDIPFile(at: gdipFile) - for dep in deps { - print("PoingAdMob: Found dependency \(dep.product) from \(dep.url)") - if !seenURLs.contains(dep.url) { - if dep.mode == "exact" { - packageDependencies.append(.package(url: dep.url, exact: Version(stringLiteral: dep.version))) - } else if dep.mode == "from" { - packageDependencies.append(.package(url: dep.url, from: Version(stringLiteral: dep.version))) - } else if dep.mode == "branch" { - packageDependencies.append(.package(url: dep.url, branch: dep.version)) - } - seenURLs.insert(dep.url) + let spmPackages = parseGDIPFile(at: gdipFile) + for package in spmPackages { + print("PoingAdMob: Found package \(package.url) v\(package.version) → \(package.products)") + if !seenURLs.contains(package.url) { + packageDependencies.append(.package(url: package.url, exact: Version(stringLiteral: package.version))) + seenURLs.insert(package.url) } - - if !seenProducts.contains(dep.product) && !dep.product.isEmpty { - let packageName = dep.url.components(separatedBy: "/").last? - .replacingOccurrences(of: ".git", with: "") ?? "" - targetDependencies.append(.product(name: dep.product, package: packageName)) - seenProducts.insert(dep.product) + + let packageName = package.url.components(separatedBy: "/").last? + .replacingOccurrences(of: ".git", with: "") ?? "" + for product in package.products { + if !seenProducts.contains(product) { + targetDependencies.append(.product(name: product, package: packageName)) + seenProducts.insert(product) + } } } } diff --git a/platforms/ios/src/ads/config/package.gd b/platforms/ios/src/ads/config/package.gd index 2696fc2fd..1c2f0ce5e 100644 --- a/platforms/ios/src/ads/config/package.gd +++ b/platforms/ios/src/ads/config/package.gd @@ -27,4 +27,4 @@ ## [br][b]Note:[/b] This file is READ-ONLY for manual edits during releases. ## Current version of the plugin in Semantic Versioning (SemVer) format. -const VERSION := "4.1.0" # READ-ONLY +const VERSION := "4.1.1" # READ-ONLY diff --git a/platforms/ios/src/ads/config/poing-godot-admob-ads.gdip b/platforms/ios/src/ads/config/poing-godot-admob-ads.gdip index 2b93b1fc9..dc6c3245f 100644 --- a/platforms/ios/src/ads/config/poing-godot-admob-ads.gdip +++ b/platforms/ios/src/ads/config/poing-godot-admob-ads.gdip @@ -12,9 +12,12 @@ system=["AppTrackingTransparency.framework"] capabilities=[] files=[] linker_flags=["-ObjC"] -admob_packages=[ - "https://github.com/googleads/swift-package-manager-google-mobile-ads.git@exact:12.14.0|GoogleMobileAds", - "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git@exact:3.1.0|GoogleUserMessagingPlatform" +spm_packages=[ + { + "url": "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", + "version": "12.14.0", + "products": ["GoogleMobileAds"] + } ] [plist] diff --git a/platforms/ios/src/mediation/meta/config/poing-godot-admob-meta.gdip b/platforms/ios/src/mediation/meta/config/poing-godot-admob-meta.gdip index a0774e832..7d2730f5a 100644 --- a/platforms/ios/src/mediation/meta/config/poing-godot-admob-meta.gdip +++ b/platforms/ios/src/mediation/meta/config/poing-godot-admob-meta.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-meta.git@exact:6.20.100|MetaAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-meta.git", + "version": "6.20.100", + "products": ["MetaAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/vungle/config/poing-godot-admob-vungle.gdip b/platforms/ios/src/mediation/vungle/config/poing-godot-admob-vungle.gdip index 242045cf3..96744f5bc 100644 --- a/platforms/ios/src/mediation/vungle/config/poing-godot-admob-vungle.gdip +++ b/platforms/ios/src/mediation/vungle/config/poing-godot-admob-vungle.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-liftoffmonetize.git@exact:7.5.300|LiftoffMonetizeAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-liftoffmonetize.git", + "version": "7.5.300", + "products": ["LiftoffMonetizeAdapterTarget"] + } ] [plist] From 2d7ef92010bc5e96558dea21635e495a229a30c2 Mon Sep 17 00:00:00 2001 From: Gustavo Maciel Date: Sat, 21 Mar 2026 20:49:48 -0300 Subject: [PATCH 2/6] docs: Add primary branch and GitHub CLI usage information to AGENTS.md. --- AGENTS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index b81ff279b..a59cb8ac8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,6 +4,7 @@ This file is the authoritative source of truth for ALL AI agents (Gemini, Claude **Read this first** to minimize token usage and ensure architectural consistency. ## 🏗️ Repository Architecture +- **Primary Branch:** `master` - **GDScript (Core):** `platforms/godot_editor/addons/admob/` - `admob.gd`: Main entry point. - `internal/`: Logic. **Rule: No `class_name` here, use `preload`.** @@ -20,6 +21,7 @@ This file is the authoritative source of truth for ALL AI agents (Gemini, Claude - *Example (All):* `./scripts/build_local.sh all 4.6.1` - *Example (iOS):* `./scripts/build_local.sh ios 4.6.1` - *Example (Android):* `./scripts/build_local.sh android 4.6.1` +- **GitHub CLI:** Use `gh` to check status of `issues` or `prs`. ## 📝 Coding Standards - **License Header:** EVERY new file MUST start with the project's MIT License header. From 99d81fde24ae58e90a9d14a8b330e963d635e9c4 Mon Sep 17 00:00:00 2001 From: Gustavo Maciel Date: Sat, 21 Mar 2026 21:10:07 -0300 Subject: [PATCH 3/6] Refactor: Update AdMob SPM package definitions to a new structured format and remove the UMP dependency. --- platforms/ios/src/ads/config/poing-godot-admob-ads.gdip | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/platforms/ios/src/ads/config/poing-godot-admob-ads.gdip b/platforms/ios/src/ads/config/poing-godot-admob-ads.gdip index ad9a8c2fd..db42b7db8 100644 --- a/platforms/ios/src/ads/config/poing-godot-admob-ads.gdip +++ b/platforms/ios/src/ads/config/poing-godot-admob-ads.gdip @@ -12,9 +12,12 @@ system=["AppTrackingTransparency.framework"] capabilities=[] files=[] linker_flags=["-ObjC"] -admob_packages=[ - "https://github.com/googleads/swift-package-manager-google-mobile-ads.git@exact:13.1.0|GoogleMobileAds", - "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git@exact:3.1.0|GoogleUserMessagingPlatform" +spm_packages=[ + { + "url": "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", + "version": "13.1.0", + "products": ["GoogleMobileAds"] + } ] [plist] From 0be93c9a78b2419716963b65c70de385d13b8d3f Mon Sep 17 00:00:00 2001 From: Gustavo Maciel Date: Sun, 5 Jul 2026 13:48:53 -0300 Subject: [PATCH 4/6] feat: implement iOS export plugin to automatically handle Swift Package Manager dependencies --- .../internal/exporters/ios/export_plugin.gd | 209 ++++++++++++++++++ .../admob/internal/services/export_service.gd | 56 +++++ .../internal/services/pbxproj_service.gd | 140 ++++++++++++ 3 files changed, 405 insertions(+) create mode 100644 platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd create mode 100644 platforms/godot_editor/addons/admob/internal/services/export_service.gd create mode 100644 platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd diff --git a/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd b/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd new file mode 100644 index 000000000..4b5ed69f3 --- /dev/null +++ b/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd @@ -0,0 +1,209 @@ +# MIT License + +# Copyright (c) 2026-present Poing Studios + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +extends EditorExportPlugin + +const ExportService := preload("res://addons/admob/internal/services/export_service.gd") +const PbxprojService := preload("res://addons/admob/internal/services/pbxproj_service.gd") +const PLUGIN_CONFIG_DIR := "res://ios/plugins/" + +var _spm_applied := false +var _pending_export_path := "" +var _spm_dependencies: Array[Dictionary] = [] + + +func _get_name() -> String: + return "PoingAdMobIOS" + + +func _supports_platform(platform: EditorExportPlatform) -> bool: + return platform.get_os_name() == "iOS" + + +func _export_begin(features: PackedStringArray, is_debug: bool, path: String, flags: int) -> void: + _spm_applied = false + _pending_export_path = path + + +func _end_generate_apple_embedded_project(path: String, _will_build_archive: bool) -> void: + print("AdMob iOS: _end_generate_apple_embedded_project CALLED with path='%s'" % path) + _apply_spm(path, false) + + +func _export_end() -> void: + if _spm_applied or _pending_export_path.is_empty(): + return + print("AdMob iOS: _export_end fallback (pre-4.7 engine) with path='%s'" % _pending_export_path) + _apply_spm(_pending_export_path, true) + + +func _apply_spm(path: String, defer_patch: bool) -> void: + var version_info := Engine.get_version_info() + var is_lower_than_4_8 := (version_info.major < 4) or (version_info.major == 4 and version_info.minor < 8) + if not is_lower_than_4_8: + print("AdMob iOS: Godot 4.8+ detected, utilizing native SPM support. Skipping custom SPM export pipeline.") + return + + _spm_applied = true + var activated_plugins := ExportService.get_activated_plugins("iOS") + if activated_plugins.is_empty(): + print("AdMob iOS: No activated plugins found.") + return + + _spm_dependencies = _collect_spm_dependencies(activated_plugins) + if _spm_dependencies.is_empty(): + print("AdMob iOS: No SPM dependencies collected.") + return + + var export_dir := path.get_base_dir() + _generate_package_swift(export_dir, _spm_dependencies) + print("AdMob iOS: Package.swift generated.") + _generate_dummy_source(export_dir) + print("AdMob iOS: Dummy.swift generated.") + + if defer_patch: + print("AdMob iOS: Deferring Xcode project patch...") + _defer_pbxproj_patch.call_deferred(export_dir, path) + else: + _patch_xcodeproj(export_dir, path) + print("AdMob iOS: Xcode project patched.") + _spm_dependencies.clear() + + +func _defer_pbxproj_patch(export_dir: String, path: String) -> void: + _patch_xcodeproj(export_dir, path) + print("AdMob iOS: Deferred Xcode project patch applied.") + _spm_dependencies.clear() + + +func _patch_xcodeproj(export_dir: String, path: String) -> void: + var project_name := path.get_file().get_basename() + var pbxproj_path := export_dir.path_join(project_name + ".xcodeproj/project.pbxproj") + + if FileAccess.file_exists(pbxproj_path): + PbxprojService.patch(pbxproj_path) + return + + var dir := DirAccess.open(export_dir) + if not dir: + push_warning("AdMob: Could not open export directory: %s" % export_dir) + return + + dir.list_dir_begin() + var file_name := dir.get_next() + while file_name != "": + if file_name.ends_with(".xcodeproj"): + var found_path := export_dir.path_join(file_name).path_join("project.pbxproj") + if FileAccess.file_exists(found_path): + PbxprojService.patch(found_path) + else: + push_warning("AdMob: project.pbxproj not found at: %s" % found_path) + break + file_name = dir.get_next() + + +func _collect_spm_dependencies(activated_plugins: Array[String]) -> Array[Dictionary]: + var deps: Array[Dictionary] = [] + var dir := DirAccess.open(PLUGIN_CONFIG_DIR) + if not dir: + return deps + + dir.list_dir_begin() + var file_name := dir.get_next() + while file_name != "": + if not dir.current_is_dir() and file_name.ends_with(".gdip"): + var config := ConfigFile.new() + var err := config.load(PLUGIN_CONFIG_DIR.path_join(file_name)) + if err == OK: + var plugin_name := config.get_value("config", "name", "") + if activated_plugins.has(plugin_name): + if config.has_section_key("dependencies", "spm_packages"): + var packages: Array = config.get_value("dependencies", "spm_packages", []) + for pkg: Dictionary in packages: + var url: String = pkg.get("url", "") + var version: String = pkg.get("version", "") + var products: Array = pkg.get("products", []) + for product: String in products: + var dep := { + "url": url, + "version": version, + "kind": "exact", + "product": product + } + deps.append(dep) + file_name = dir.get_next() + return deps + + +func _generate_package_swift(export_dir: String, dependencies: Array[Dictionary]) -> void: + var package_dir := export_dir.path_join("admob_spm") + if not DirAccess.dir_exists_absolute(package_dir): + DirAccess.make_dir_recursive_absolute(package_dir) + + var package_deps_str := "" + var target_deps_str := "" + var processed_urls := [] + var processed_products := [] + + for dep in dependencies: + var url: String = dep.url + var product: String = dep.product + var package_name: String = url.get_file().trim_suffix(".git") + + if not processed_urls.has(url): + processed_urls.append(url) + var version_rule := ( + 'exact: "%s"' % dep.version if dep.kind == "exact" else 'from: "%s"' % dep.version + ) + package_deps_str += ' .package(url: "%s", %s),\n' % [url, version_rule] + + if not processed_products.has(product): + processed_products.append(product) + target_deps_str += ( + ' .product(name: "%s", package: "%s"),\n' % [product, package_name] + ) + + var content := ( + '// swift-tools-version:5.9\nimport PackageDescription\n\nlet package = Package(\n name: "PoingGodotAdMobDeps",\n platforms: [.iOS(.v14)],\n products: [\n .library(\n name: "PoingGodotAdMobDeps",\n targets: ["PoingGodotAdMobDeps"]),\n ],\n dependencies: [\n' + + package_deps_str + + ' ],\n targets: [\n .target(\n name: "PoingGodotAdMobDeps",\n dependencies: [\n' + + target_deps_str + + ' ],\n path: "PoingGodotAdMobDeps"\n )\n ]\n)\n' + ) + + var file := FileAccess.open(package_dir.path_join("Package.swift"), FileAccess.WRITE) + if file: + file.store_string(content) + file.close() + print("AdMob: Generated Package.swift at %s" % package_dir) + + +func _generate_dummy_source(export_dir: String) -> void: + var source_dir := export_dir.path_join("admob_spm/PoingGodotAdMobDeps") + if not DirAccess.dir_exists_absolute(source_dir): + DirAccess.make_dir_recursive_absolute(source_dir) + + var content := "// Dummy\nimport Foundation\n\npublic struct PoingGodotAdMobDeps {\n public init() {}\n}\n" + var file := FileAccess.open(source_dir.path_join("Dummy.swift"), FileAccess.WRITE) + if file: + file.store_string(content) + file.close() diff --git a/platforms/godot_editor/addons/admob/internal/services/export_service.gd b/platforms/godot_editor/addons/admob/internal/services/export_service.gd new file mode 100644 index 000000000..6b786db78 --- /dev/null +++ b/platforms/godot_editor/addons/admob/internal/services/export_service.gd @@ -0,0 +1,56 @@ +# MIT License + +# Copyright (c) 2026-present Poing Studios + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +const EXPORT_PRESETS_PATH := "res://export_presets.cfg" + + +static func get_activated_plugins(platform_name: String) -> Array[String]: + var activated_plugins: Array[String] = [] + + if not FileAccess.file_exists(EXPORT_PRESETS_PATH): + return activated_plugins + + var config := ConfigFile.new() + var err := config.load(EXPORT_PRESETS_PATH) + if err != OK: + return activated_plugins + + for section in config.get_sections(): + if not section.begins_with("preset."): + continue + + var platform = config.get_value(section, "platform", "") + if platform != platform_name: + continue + + # Check options for this preset + var options_section = section + ".options" + if config.has_section(options_section): + for key in config.get_section_keys(options_section): + if key.begins_with("plugins/"): + var is_enabled = config.get_value(options_section, key, false) + if is_enabled: + var plugin_name = key.trim_prefix("plugins/") + if not activated_plugins.has(plugin_name): + activated_plugins.append(plugin_name) + + return activated_plugins diff --git a/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd b/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd new file mode 100644 index 000000000..9fb6ff871 --- /dev/null +++ b/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd @@ -0,0 +1,140 @@ +# MIT License +# +# Copyright (c) 2026-present Poing Studios +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +static func patch(path: String) -> void: + var content := FileAccess.get_file_as_string(path) + if content.is_empty(): + return + + if content.contains("AD0000000000000000000001"): + return + + var local_ref_id := "AD0000000000000000000001" + var product_dep_id := "AD0000000000000000000002" + var build_file_id := "AD0000000000000000000003" + + if not content.contains("/* Begin XCLocalSwiftPackageReference section */"): + content = ( + content + . replace( + "/* End PBXGroup section */", + "/* End PBXGroup section */\n\n/* Begin XCLocalSwiftPackageReference section */\n/* End XCLocalSwiftPackageReference section */" + ) + ) + + if not content.contains("/* Begin XCSwiftPackageProductDependency section */"): + content = ( + content + . replace( + "/* End XCLocalSwiftPackageReference section */", + "/* End XCLocalSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n/* End XCSwiftPackageProductDependency section */" + ) + ) + + var local_ref_def := ( + " " + + local_ref_id + + ' /* XCLocalSwiftPackageReference "admob_spm" */ = {\n isa = XCLocalSwiftPackageReference;\n relativePath = "admob_spm";\n };\n' + ) + content = content.replace( + "/* End XCLocalSwiftPackageReference section */", + local_ref_def + "/* End XCLocalSwiftPackageReference section */" + ) + + var product_dep_def := ( + " " + + product_dep_id + + " /* PoingGodotAdMobDeps */ = {\n isa = XCSwiftPackageProductDependency;\n package = " + + local_ref_id + + ' /* XCLocalSwiftPackageReference "admob_spm" */;\n productName = "PoingGodotAdMobDeps";\n };\n' + ) + content = content.replace( + "/* End XCSwiftPackageProductDependency section */", + product_dep_def + "/* End XCSwiftPackageProductDependency section */" + ) + + var build_file_def := ( + " " + + build_file_id + + " /* PoingGodotAdMobDeps in Frameworks */ = {isa = PBXBuildFile; productRef = " + + product_dep_id + + " /* PoingGodotAdMobDeps */; };\n" + ) + content = content.replace( + "/* Begin PBXBuildFile section */", "/* Begin PBXBuildFile section */\n" + build_file_def + ) + + if content.contains("packageReferences = ("): + content = content.replace( + "packageReferences = (", + ( + "packageReferences = (\n " + + local_ref_id + + ' /* XCLocalSwiftPackageReference "admob_spm" */,' + ) + ) + else: + content = ( + content + . replace( + "productRefGroup =", + ( + "packageReferences = (\n " + + local_ref_id + + ' /* XCLocalSwiftPackageReference "admob_spm" */,\n );\n productRefGroup =' + ) + ) + ) + + if content.contains("packageProductDependencies = ("): + content = content.replace( + "packageProductDependencies = (", + ( + "packageProductDependencies = (\n " + + product_dep_id + + " /* PoingGodotAdMobDeps */," + ) + ) + else: + content = content.replace( + "buildRules = (", + ( + "packageProductDependencies = (\n " + + product_dep_id + + " /* PoingGodotAdMobDeps */,\n );\n buildRules = (" + ) + ) + + var framework_section_start := content.find("isa = PBXFrameworksBuildPhase;") + if framework_section_start != -1: + var files_start := content.find("files = (", framework_section_start) + if files_start != -1: + content = content.insert( + files_start + 9, + "\n " + build_file_id + " /* PoingGodotAdMobDeps in Frameworks */," + ) + + var file := FileAccess.open(path, FileAccess.WRITE) + if file: + file.store_string(content) + file.close() + print("AdMob: Patched project.pbxproj with SPM dependencies") From fae1718a32e5a9be279cf0ba7bdd32db4de66e4f Mon Sep 17 00:00:00 2001 From: Gustavo Maciel Date: Sun, 5 Jul 2026 22:27:45 -0300 Subject: [PATCH 5/6] refactor: migrate mediation config format to structured spm_packages array --- platforms/godot_editor/addons/admob/admob.gd | 3 +++ .../addons/admob/internal/exporters/ios/export_plugin.gd | 8 ++------ .../addons/admob/internal/services/export_service.gd.uid | 1 + .../addons/admob/internal/services/pbxproj_service.gd.uid | 1 + .../applovin/config/poing-godot-admob-applovin.gdip | 8 ++++++-- .../bidmachine/config/poing-godot-admob-bidmachine.gdip | 8 ++++++-- .../chartboost/config/poing-godot-admob-chartboost.gdip | 8 ++++++-- .../dtexchange/config/poing-godot-admob-dtexchange.gdip | 8 ++++++-- .../imobile/config/poing-godot-admob-imobile.gdip | 8 ++++++-- .../mediation/inmobi/config/poing-godot-admob-inmobi.gdip | 8 ++++++-- .../src/mediation/line/config/poing-godot-admob-line.gdip | 8 ++++++-- .../src/mediation/maio/config/poing-godot-admob-maio.gdip | 8 ++++++-- .../mintegral/config/poing-godot-admob-mintegral.gdip | 8 ++++++-- .../mediation/moloco/config/poing-godot-admob-moloco.gdip | 8 ++++++-- .../mytarget/config/poing-godot-admob-mytarget.gdip | 8 ++++++-- .../mediation/pangle/config/poing-godot-admob-pangle.gdip | 8 ++++++-- .../pubmatic/config/poing-godot-admob-pubmatic.gdip | 8 ++++++-- .../unity_ads/config/poing-godot-admob-unity_ads.gdip | 8 ++++++-- 18 files changed, 91 insertions(+), 34 deletions(-) create mode 100644 platforms/godot_editor/addons/admob/internal/services/export_service.gd.uid create mode 100644 platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd.uid diff --git a/platforms/godot_editor/addons/admob/admob.gd b/platforms/godot_editor/addons/admob/admob.gd index 599bb544d..c2d69d21e 100644 --- a/platforms/godot_editor/addons/admob/admob.gd +++ b/platforms/godot_editor/addons/admob/admob.gd @@ -33,6 +33,7 @@ const ProjectSettingsService := preload( var _main_exporter := preload("res://addons/admob/internal/exporters/main_export_plugin.gd").new() var _android_exporter := preload("res://addons/admob/internal/exporters/android/export_plugin.gd").new() +var _ios_exporter := preload("res://addons/admob/internal/exporters/ios/export_plugin.gd").new() func _enter_tree() -> void: @@ -44,10 +45,12 @@ func _enter_tree() -> void: add_export_plugin(_main_exporter) add_export_plugin(_android_exporter) + add_export_plugin(_ios_exporter) add_tool_submenu_item(MENU_NAME, AdMobEditorMenu.new(self)) func _exit_tree() -> void: remove_export_plugin(_main_exporter) remove_export_plugin(_android_exporter) + remove_export_plugin(_ios_exporter) remove_tool_menu_item(MENU_NAME) diff --git a/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd b/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd index 4b5ed69f3..a43d607c0 100644 --- a/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd +++ b/platforms/godot_editor/addons/admob/internal/exporters/ios/export_plugin.gd @@ -55,10 +55,9 @@ func _export_end() -> void: print("AdMob iOS: _export_end fallback (pre-4.7 engine) with path='%s'" % _pending_export_path) _apply_spm(_pending_export_path, true) - func _apply_spm(path: String, defer_patch: bool) -> void: var version_info := Engine.get_version_info() - var is_lower_than_4_8 := (version_info.major < 4) or (version_info.major == 4 and version_info.minor < 8) + var is_lower_than_4_8: bool = (version_info.major < 4) or (version_info.major == 4 and version_info.minor < 8) if not is_lower_than_4_8: print("AdMob iOS: Godot 4.8+ detected, utilizing native SPM support. Skipping custom SPM export pipeline.") return @@ -146,7 +145,6 @@ func _collect_spm_dependencies(activated_plugins: Array[String]) -> Array[Dictio var dep := { "url": url, "version": version, - "kind": "exact", "product": product } deps.append(dep) @@ -171,9 +169,7 @@ func _generate_package_swift(export_dir: String, dependencies: Array[Dictionary] if not processed_urls.has(url): processed_urls.append(url) - var version_rule := ( - 'exact: "%s"' % dep.version if dep.kind == "exact" else 'from: "%s"' % dep.version - ) + var version_rule := 'exact: "%s"' % dep.version package_deps_str += ' .package(url: "%s", %s),\n' % [url, version_rule] if not processed_products.has(product): diff --git a/platforms/godot_editor/addons/admob/internal/services/export_service.gd.uid b/platforms/godot_editor/addons/admob/internal/services/export_service.gd.uid new file mode 100644 index 000000000..299b9f8c0 --- /dev/null +++ b/platforms/godot_editor/addons/admob/internal/services/export_service.gd.uid @@ -0,0 +1 @@ +uid://nqvkeeah3wtc diff --git a/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd.uid b/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd.uid new file mode 100644 index 000000000..2b4e59ba3 --- /dev/null +++ b/platforms/godot_editor/addons/admob/internal/services/pbxproj_service.gd.uid @@ -0,0 +1 @@ +uid://6ys84i6rthok diff --git a/platforms/ios/src/mediation/applovin/config/poing-godot-admob-applovin.gdip b/platforms/ios/src/mediation/applovin/config/poing-godot-admob-applovin.gdip index 6be3025a5..cc5c890b6 100644 --- a/platforms/ios/src/mediation/applovin/config/poing-godot-admob-applovin.gdip +++ b/platforms/ios/src/mediation/applovin/config/poing-godot-admob-applovin.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-applovin.git@exact:13.6.300|AppLovinAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-applovin.git", + "version": "13.6.300", + "products": ["AppLovinAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/bidmachine/config/poing-godot-admob-bidmachine.gdip b/platforms/ios/src/mediation/bidmachine/config/poing-godot-admob-bidmachine.gdip index c248457fd..8e4da7aae 100644 --- a/platforms/ios/src/mediation/bidmachine/config/poing-godot-admob-bidmachine.gdip +++ b/platforms/ios/src/mediation/bidmachine/config/poing-godot-admob-bidmachine.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-bidmachine.git@exact:3.7.000|BidMachineAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-bidmachine.git", + "version": "3.7.000", + "products": ["BidMachineAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/chartboost/config/poing-godot-admob-chartboost.gdip b/platforms/ios/src/mediation/chartboost/config/poing-godot-admob-chartboost.gdip index e16e2afef..cf11f602f 100644 --- a/platforms/ios/src/mediation/chartboost/config/poing-godot-admob-chartboost.gdip +++ b/platforms/ios/src/mediation/chartboost/config/poing-godot-admob-chartboost.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-chartboost.git@exact:9.12.0|ChartboostAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-chartboost.git", + "version": "9.12.0", + "products": ["ChartboostAdapterTarget"] + } ] [plist] \ No newline at end of file diff --git a/platforms/ios/src/mediation/dtexchange/config/poing-godot-admob-dtexchange.gdip b/platforms/ios/src/mediation/dtexchange/config/poing-godot-admob-dtexchange.gdip index a3f32f245..c498e3770 100644 --- a/platforms/ios/src/mediation/dtexchange/config/poing-godot-admob-dtexchange.gdip +++ b/platforms/ios/src/mediation/dtexchange/config/poing-godot-admob-dtexchange.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-dtexchange.git@exact:8.4.701|DTExchangeAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-dtexchange.git", + "version": "8.4.701", + "products": ["DTExchangeAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/imobile/config/poing-godot-admob-imobile.gdip b/platforms/ios/src/mediation/imobile/config/poing-godot-admob-imobile.gdip index c68c4a155..4f8a66644 100644 --- a/platforms/ios/src/mediation/imobile/config/poing-godot-admob-imobile.gdip +++ b/platforms/ios/src/mediation/imobile/config/poing-godot-admob-imobile.gdip @@ -11,8 +11,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-imobile.git@exact:2.3.407|IMobileAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-imobile.git", + "version": "2.3.407", + "products": ["IMobileAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/inmobi/config/poing-godot-admob-inmobi.gdip b/platforms/ios/src/mediation/inmobi/config/poing-godot-admob-inmobi.gdip index 45c296b16..1e980f1c3 100644 --- a/platforms/ios/src/mediation/inmobi/config/poing-godot-admob-inmobi.gdip +++ b/platforms/ios/src/mediation/inmobi/config/poing-godot-admob-inmobi.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-inmobi.git@exact:11.3.000|InMobiAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-inmobi.git", + "version": "11.3.000", + "products": ["InMobiAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/line/config/poing-godot-admob-line.gdip b/platforms/ios/src/mediation/line/config/poing-godot-admob-line.gdip index 9bfedca07..d2652832b 100644 --- a/platforms/ios/src/mediation/line/config/poing-godot-admob-line.gdip +++ b/platforms/ios/src/mediation/line/config/poing-godot-admob-line.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-line.git@exact:3.0.102|LineAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-line.git", + "version": "3.0.102", + "products": ["LineAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/maio/config/poing-godot-admob-maio.gdip b/platforms/ios/src/mediation/maio/config/poing-godot-admob-maio.gdip index 58143c002..121c75cb8 100644 --- a/platforms/ios/src/mediation/maio/config/poing-godot-admob-maio.gdip +++ b/platforms/ios/src/mediation/maio/config/poing-godot-admob-maio.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-maio.git@exact:2.2.0|MaioAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-maio.git", + "version": "2.2.0", + "products": ["MaioAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/mintegral/config/poing-godot-admob-mintegral.gdip b/platforms/ios/src/mediation/mintegral/config/poing-godot-admob-mintegral.gdip index 36e7099ca..2e2729b92 100644 --- a/platforms/ios/src/mediation/mintegral/config/poing-godot-admob-mintegral.gdip +++ b/platforms/ios/src/mediation/mintegral/config/poing-godot-admob-mintegral.gdip @@ -11,8 +11,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-mintegral.git@exact:8.1.500|MintegralAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-mintegral.git", + "version": "8.1.500", + "products": ["MintegralAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/moloco/config/poing-godot-admob-moloco.gdip b/platforms/ios/src/mediation/moloco/config/poing-godot-admob-moloco.gdip index 56b4c11e1..4a916b6e2 100644 --- a/platforms/ios/src/mediation/moloco/config/poing-godot-admob-moloco.gdip +++ b/platforms/ios/src/mediation/moloco/config/poing-godot-admob-moloco.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-moloco.git@exact:4.7.000|MolocoAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-moloco.git", + "version": "4.7.000", + "products": ["MolocoAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/mytarget/config/poing-godot-admob-mytarget.gdip b/platforms/ios/src/mediation/mytarget/config/poing-godot-admob-mytarget.gdip index 624760a33..5b1833e08 100644 --- a/platforms/ios/src/mediation/mytarget/config/poing-godot-admob-mytarget.gdip +++ b/platforms/ios/src/mediation/mytarget/config/poing-godot-admob-mytarget.gdip @@ -11,8 +11,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-mytarget.git@exact:5.44.100|MyTargetAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-mytarget.git", + "version": "5.44.100", + "products": ["MyTargetAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/pangle/config/poing-godot-admob-pangle.gdip b/platforms/ios/src/mediation/pangle/config/poing-godot-admob-pangle.gdip index 3ef651339..da799b193 100644 --- a/platforms/ios/src/mediation/pangle/config/poing-godot-admob-pangle.gdip +++ b/platforms/ios/src/mediation/pangle/config/poing-godot-admob-pangle.gdip @@ -11,8 +11,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-pangle.git@exact:8.1.00600|PangleAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-pangle.git", + "version": "8.1.00600", + "products": ["PangleAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/pubmatic/config/poing-godot-admob-pubmatic.gdip b/platforms/ios/src/mediation/pubmatic/config/poing-godot-admob-pubmatic.gdip index ca7b9f9a1..81c566565 100644 --- a/platforms/ios/src/mediation/pubmatic/config/poing-godot-admob-pubmatic.gdip +++ b/platforms/ios/src/mediation/pubmatic/config/poing-godot-admob-pubmatic.gdip @@ -11,8 +11,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-pubmatic.git@exact:5.1.100|PubMaticAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-pubmatic.git", + "version": "5.1.100", + "products": ["PubMaticAdapterTarget"] + } ] [plist] diff --git a/platforms/ios/src/mediation/unity_ads/config/poing-godot-admob-unity_ads.gdip b/platforms/ios/src/mediation/unity_ads/config/poing-godot-admob-unity_ads.gdip index e2729ab6d..559af0854 100644 --- a/platforms/ios/src/mediation/unity_ads/config/poing-godot-admob-unity_ads.gdip +++ b/platforms/ios/src/mediation/unity_ads/config/poing-godot-admob-unity_ads.gdip @@ -12,8 +12,12 @@ system=[] capabilities=[] files=[] linker_flags=[] -admob_packages=[ - "https://github.com/googleads/googleads-mobile-ios-mediation-unity.git@exact:4.18.100|UnityAdapterTarget" +spm_packages=[ + { + "url": "https://github.com/googleads/googleads-mobile-ios-mediation-unity.git", + "version": "4.18.100", + "products": ["UnityAdapterTarget"] + } ] [plist] From fd6dbdc77fbe84256ed3a9aca8d4ced506a93095 Mon Sep 17 00:00:00 2001 From: Gustavo Maciel Date: Mon, 6 Jul 2026 00:00:13 -0300 Subject: [PATCH 6/6] chore: update resource UIDs, add scene node unique IDs, and improve local build cleanup scripts. --- scripts/build_local.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/build_local.sh b/scripts/build_local.sh index eae57fe37..b406eb7b7 100755 --- a/scripts/build_local.sh +++ b/scripts/build_local.sh @@ -71,8 +71,9 @@ build_android() { chmod +x gradlew if [ "$CLEAN" = true ]; then - echo ">>> Cleaning Android build..." + echo ">>> Cleaning Android build and export directories..." ./gradlew clean || exit 1 + rm -rf "$DEST/addons/admob/android/bin/"* fi ./gradlew build -PgodotVersion="$GODOT_VERSION" && \ @@ -84,6 +85,8 @@ build_ios() { BUILD_OPTS="" if [ "$CLEAN" = true ]; then BUILD_OPTS="--clean" + echo ">>> Cleaning iOS export directories..." + rm -rf "$DEST/ios/plugins/"* fi cd "$ROOT_DIR/platforms/ios" && ./scripts/build.sh $BUILD_OPTS "$GODOT_VERSION" || exit 1