You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift新手遇含应用内评分与日志的App Xcode链接错误求助

问题描述

作为Swift新手,在运行集成应用内评分(In-App Review)与日志(Logging)功能的Godot引擎iOS插件时,Xcode出现链接错误:

ld: Undefined symbols:
os.Logger.logObject.getter : __C.OS_os_log, referenced from:
(1) suspend resume partial function for closure #1 @Sendable () async -> () in static godot_plugin.SwiftClass.launch_review_flow() -> () in InappReviewPlugin.a4
(3) suspend resume partial function for closure #1 @Sendable () async -> () in static godot_plugin.SwiftClass.launch_review_flow() -> () in InappReviewPlugin.a4
os.Logger.init() -> os.Logger, referenced from:
one-time initialization function for logger in InappReviewPlugin.a4
type metadata accessor for os.Logger, referenced from:
one-time initialization function for logger in InappReviewPlugin.a4
(1) suspend resume partial function for closure #1 @Sendable () async -> () in static godot_plugin.SwiftClass.launch_review_flow() -> () in InappReviewPlugin.a4

插件Swift代码基于StoreKit实现应用内评分功能:

import Foundation
import SwiftUI
import OSLog
import StoreKit

@available(iOS 16.0, *)
extension UIApplication {
    class func getTopViewController(base: UIViewController? = UIApplication.shared.windows.first { $0.isKeyWindow }?.rootViewController) -> UIViewController? {
        if let nav = base as? UINavigationController {
            return getTopViewController(base: nav.visibleViewController)

        } else if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
            return getTopViewController(base: selected)

        } else if let presented = base?.presentedViewController {
            return getTopViewController(base: presented)
        }
        return base
    }
}

@available(iOS 16.0, *)
extension UIViewController {
    /// Request a App Store review from the user
    /// 
    /// - Parameters:
    ///     - delay: The number of seconds this function will wait before showing the modal.
    func requestReview(delay: Double) {
        Task {
            // Use the equation n * 10^9 to convert seconds to nanoseconds.
            try? await Task.sleep(nanoseconds: UInt64(delay * pow(10.0, 9.0)))
            if let windowScene = self.view.window?.windowScene,
                self.navigationController?.topViewController == self {
                SKStoreReviewController.requestReview(in: windowScene)
            }
        }
    }
}

@available(iOS 16.0, *)
@objcMembers public class SwiftClass : NSObject
{
    static let logger = Logger()

    static func launch_review_flow() {
        Task {
            logger.info("SwiftClass: launch_review_flow(): Task")
            if let topVC = await UIApplication.getTopViewController() {
                logger.info("SwiftClass: launch_review_flow(): Task: topVC")
                await topVC.requestReview(delay: 1.5)
            }
        }
    }
}

已知问题与Logger及await语句相关,但多次尝试修复失败,需解决链接错误并获取代码优化建议。

解决方案

1. 修复OSLogger链接错误

链接错误核心原因是OSLog框架未被正确链接到插件目标,或Godot插件编译配置缺少OSLog支持,可通过以下步骤解决:

  • 添加OSLog框架:在Xcode插件目标的Build Phases -> Link Binary With Libraries中,点击+搜索并添加OSLog.framework。
  • 验证iOS版本:Logger要求iOS 14.0+,代码已标注iOS 16.0+,需确保插件Deployment Target设置为16.0或更高。
  • 关闭死代码剥离:若上述步骤无效,在插件目标Build Settings中,将Dead Code Stripping设为NO,避免编译器误删OSLog相关符号。

2. 代码优化建议

(1)Logger初始化优化

显式指定日志子系统和分类,方便后续日志筛选:

static let logger = Logger(subsystem: "com.yourcompany.godot-plugin", category: "InAppReview")

(2)异步睡眠简化

用Task.sleep(for:)替代手动浮点转换,避免计算误差:

// 原代码
try? await Task.sleep(nanoseconds: UInt64(delay * pow(10.0, 9.0)))
// 优化后
try? await Task.sleep(for: .seconds(delay))

(3)顶层视图控制器获取优化

适配iOS 13+的UIWindowScene方案,替代旧的UIApplication.shared.windows:

@available(iOS 16.0, *)
extension UIApplication {
    class func getTopViewController() -> UIViewController? {
        guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
              let rootVC = windowScene.windows.first?.rootViewController else {
            return nil
        }
        
        var topVC = rootVC
        while let presentedVC = topVC.presentedViewController {
            topVC = presentedVC
            if let navVC = topVC as? UINavigationController {
                topVC = navVC.visibleViewController ?? topVC
            } else if let tabVC = topVC as? UITabBarController {
                topVC = tabVC.selectedViewController ?? topVC
            }
        }
        return topVC
    }
}

(4)评分请求条件增强

添加可用性检查与错误日志,提升鲁棒性:

@available(iOS 16.0, *)
extension UIViewController {
    func requestReview(delay: Double) {
        guard SKStoreReviewController.isAvailable else {
            SwiftClass.logger.error("应用内评分当前不可用")
            return
        }
        Task {
            try? await Task.sleep(for: .seconds(delay))
            guard let windowScene = view.window?.windowScene else {
                SwiftClass.logger.error("无法获取当前窗口场景")
                return
            }
            SKStoreReviewController.requestReview(in: windowScene)
        }
    }
}

(5)异步函数调用简化

移除不必要的await(getTopViewController并非异步函数),精简代码:

static func launch_review_flow() {
    Task {
        logger.info("启动应用内评分流程")
        guard let topVC = UIApplication.getTopViewController() else {
            logger.error("无法获取顶层视图控制器")
            return
        }
        await topVC.requestReview(delay: 1.5)
    }
}

内容的提问来源于stack exchange,提问作者Cengiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 07:45:22