IOS版本升级适配

iOS18适配

2024-10-07  本文已影响0人  来不及变坏

一、开发iOS18的Controls控制组件

在 iOS18 中,你可以将应用的控件扩展到系统级别,使其出现在控制中心、锁定屏幕等位置。本文将详细介绍如何使用 WidgetKit 构建和定制控件,并让控件支持配置,最终将其添加到系统界面中。

1.1前期准备

在开始之前,确保你已经在 Xcode 中创建了一个 iOS 项目,并安装了最新版本的 Xcode。你还需要一些基本的 Swift 和 SwiftUI 知识。

1.2将控件添加到 Widget Bundle

1.2.1什么是 Widget Bundle?

Widget Bundle 是一种容器,允许你将多个控件组合在一起。通过将控件添加到 Widget Bundle,你可以更好地组织和管理这些控件,并方便地在应用中启用或禁用它们。

1.2.2创建一个 Widget Bundle

我们需要定义一个 WidgetBundle 来包含我们的控件。以下是具体的代码示例:

@main
struct ProductivityExtensionBundle: WidgetBundle {
    
    var body: some Widget {
        ChecklistWidget()  // 添加清单控件
        TaskCounterWidget()  // 添加任务计数控件
        TimerToggle()  // 添加定时器切换控件
    }
    
}

1.2.3 控件的添加

在 body 中,我们添加了三个控件:

1.3构建控件

1.3.1创建控件的基础结构

我们将使用 ControlWidget 协议来定义一个基础控件。这里我们以定时器切换控件为例进行说明。

struct TimerToggle: ControlWidget {
    var body: some ControlWidgetConfiguration {
        StaticControlConfiguration(
            kind: "com.apple.Productivity.TimerToggle"
        ) {
            ControlWidgetToggle(
                "Work Timer",
                isOn: TimerManager.shared.isRunning,
                action: ToggleTimerIntent()
            ) { isOn in
                Image(systemName: isOn
                      ? "hourglass"
                      : "hourglass.bottomhalf.filled")
            }
        }
    }
}

1.3.2控件的工作原理

这个控件的核心是一个切换按钮。根据定时器的运行状态(isOn),显示不同的图标(如沙漏或空心沙漏),并执行相应的操作(启动或停止定时器)。

1.3.3控件配置的关键点

1.4自定义控件外观

1.4.1指定不同的符号

为了增强用户体验,我们可以根据定时器的状态显示不同的符号(例如:定时器运行时显示沙漏,停止时显示半沙漏)。

struct TimerToggle: ControlWidget {
    var body: some ControlWidgetConfiguration {
        StaticControlConfiguration(
            kind: "com.apple.Productivity.TimerToggle"
        ) {
            ControlWidgetToggle(
                "Work Timer",
                isOn: TimerManager.shared.isRunning,
                action: ToggleTimerIntent()
            ) { isOn in
                Image(systemName: isOn
                      ? "hourglass"
                      : "hourglass.bottomhalf.filled")
            }
        }
    }
}

1.4.2添加自定义文本和颜色

你还可以为控件添加自定义文本和颜色,以提供更好的视觉效果和用户提示。

struct TimerToggle: ControlWidget {
    var body: some ControlWidgetConfiguration {
        StaticControlConfiguration(
            kind: "com.apple.Productivity.TimerToggle"
        ) {
            ControlWidgetToggle(
                "Work Timer",
                isOn: TimerManager.shared.isRunning,
                action: ToggleTimerIntent()
            ) { isOn in
                Label(isOn ? "Running" : "Stopped",
                      systemImage: isOn
                      ? "hourglass"
                      : "hourglass.bottomhalf.filled")
            }
            .tint(.purple)
        }
    }
}

通过这些自定义选项,你可以创建一个更加丰富和直观的控件。

1,5实现控件功能

1.5.1定义定时器切换逻辑

我们需要实现一个操作意图(Intent),用于处理定时器的启动和停止操作。

struct ToggleTimerIntent: SetValueIntent, LiveActivityIntent {
    static let title: LocalizedStringResource = "Productivity Timer"
    
    @Parameter(title: "Running")
    var value: Bool  // 定时器的运行状态
    
    func perform() throws -> some IntentResult {
        TimerManager.shared.setTimerRunning(value)
        return .result()
    }
}

1.5.2从应用内部刷新控件

当定时器状态发生变化时,我们需要刷新控件的显示,以确保其显示的状态与实际一致。

func timerManager(_ manager: TimerManager,
                  timerDidChange timer: ProductivityTimer) {
    ControlCenter.shared.reloadControls(
        ofKind: "com.apple.Productivity.TimerToggle"
    )
}

通过这种方式,你可以确保控件的显示始终与定时器的实际状态保持一致。

1.6值提供者与异步数据获取

1.6.1定义值提供者

为了提高控件的灵活性和响应性,我们可以使用值提供者(Value Provider)来动态获取控件的状态。

struct TimerValueProvider: ControlValueProvider {
    
    func currentValue() async throws -> Bool {
        try await TimerManager.shared.fetchRunningState()
    }
    
    let previewValue: Bool = false
}

1.6.2异步获取状态

我们可以将值提供者集成到控件中,以实现异步数据获取。

struct TimerToggle: ControlWidget {
    var body: some ControlWidgetConfiguration {
        StaticControlConfiguration(
            kind: "com.apple.Productivity.TimerToggle",
            provider: TimerValueProvider()
        ) { isRunning in
            ControlWidgetToggle(
                "Work Timer",
                isOn: isRunning,
                action: ToggleTimerIntent()
            ) { isOn in
                Label(isOn ? "Running" : "Stopped",
                      systemImage: isOn
                      ? "hourglass"
                      : "hourglass.bottomhalf.filled")
            }
            .tint(.purple)
        }
    }
}

通过这种方式,你可以使控件动态响应定时器状态的变化,提供更好的用户体验。

1.7使控件可配置

1.7.1定义可配置的值提供者

我们可以进一步扩展值提供者,使其支持配置不同的定时器。

struct ConfigurableTimerValueProvider: AppIntentControlValueProvider {
    func currentValue(configuration: SelectTimerIntent) async throws -> TimerState {
        let timer = configuration.timer
        let isRunning = try await TimerManager.shared.fetchTimerRunning(timer: timer)
        return TimerState(timer: timer, isRunning: isRunning)
    }
    
    func previewValue(configuration: SelectTimerIntent) -> TimerState {
        return TimerState(timer: configuration.timer, isRunning: false)
    }
}

1.7.2实现可配置的定时器控件

我们可以使用可配置的值提供者创建一个更加灵活的定时器控件。

struct TimerToggle: ControlWidget {
    var body: some ControlWidgetConfiguration {
        AppIntentControlConfiguration(
            kind: "com.apple.Productivity.TimerToggle",
            provider: ConfigurableTimerValueProvider()
        ) { timerState in
            ControlWidgetToggle(
                timerState.timer.name,
                isOn: timerState.isRunning,
                action: ToggleTimerIntent(timer: timerState.timer)
            ) { isOn in
                Label(isOn ? "Running" : "Stopped",
                      systemImage: isOn
                      ? "hourglass"
                      : "hourglass.bottomhalf.filled")
            }
            .tint(.purple)
        }
    }
}

通过这种方式,你可以创建一个更加灵活和强大的控件,允许用户根据需要配置不同的定时器。

1.8自动提示用户配置

1.8.1自动提示用户配置

为了提高用户体验,我们可以自动提示用户对控件进行配置。

struct SomeControl: ControlWidget {
    var body: some ControlWidgetConfiguration {
        AppIntentControlConfiguration(
            // 配置项
        )
        .promptsForUserConfiguration()
    }
}

通过这种方式,你可以让用户在使用控件时更加方便地进行配置,提升应用的易用性。

1.9添加控件提示与描述

1.9.1添加操作提示和描述

为了让用户更好地理解控件的功能,我们可以为控件添加操作提示和描述。

struct TimerToggle: ControlWidget {
    var body: some ControlWidgetConfiguration {
        AppIntentControlConfiguration(
            kind: "com.apple.Productivity.TimerToggle",
            provider: ConfigurableTimerValueProvider()
        ) { timerState in
            ControlWidgetToggle(
                timerState.timer.name,
                isOn: timerState.isRunning,
                action: ToggleTimerIntent(timer: timerState.timer)
            ) { isOn in
                Label(isOn ? "Running" : "Stopped",
                      systemImage: isOn
                      ? "hourglass"
                      : "hourglass.bottomhalf.filled")
                .controlWidgetActionHint(isOn ?
                                         "Start" : "Stop")
            }
            .tint(.purple)
        }
        .displayName("Productivity Timer")
        .description("Start and stop a productivity timer.")
    }
}

二、Xcode15.3 打包 HandyJSON 报错 Command SwiftCompile failed with a nonzero exit code

Xcode15.3 打包 HandyJSON 报错 《Command SwiftCompile failed with a nonzero exit code》

已经不在建议使用了

临时解决方案

1.方案一

降低Xode版本

2.方案二

暂时的解决方法是:

在 Pod 的 Target 中找到 HandyJSON, 然后设置Optimization Level为 None和No Optimization,

3.方案三

暂时需要使用的 可以使用这种方式拉取 pod 'HandyJSON', :git => 'github.com/Miles-Mathe…'

三、App Store 审核应用时出现包含 bitcode 的报错

问题描述:

在 Xcode 开发环境下,将采用网易云信相关产品适配的 iOS 客户端 SDK(例如 NERtcSDKNIMSDK)开发的应用打包提交到苹果应用商店(App Store)审核时,出现包含 Bitcode 的报错,诸如如下报错:

Invalid Executable. The executable 'XXX.app/Frameworks/NERtcSDK.framework

NERtcSDK' contains bitcode.

其中,Xcode16 报错情况较多。

问题原因

Bitcode 是一种中间表示形式,在 Xcode 中打包提交到 App Store 审核时,如果出现包含 Bitcode 的报错,这通常意味着您的应用没有正确包含 Bitcode。Bitcode 是苹果的一项要求,它允许苹果在 App Store 中对您的应用进行进一步的优化。

当提交应用到 App Store 时出现与 Bitcode 相关的问题,您需要手动移除 framework 中的 Bitcode。framework 是指 macOS 和 iOS 项目中的一个软件框架,它是一种包含代码、资源和其他文件的包,用于实现特定的功能或服务。framework 通常用于提供应用程序的某些部分,如用户界面元素、数据处理功能或其他服务。

解决方法
工具介绍

xcrun bitcode_strip 是一个命令行工具,用于手动去除对应 framework 的 Bitcode,命令格式如下:

xcrun bitcode_strip -r ${framework_path} -o ${framework_path}
${framework_path} 是一个占位符,表示 framework 的二进制文件路径。在实际使用命令时,您需要将 ${framework_path} 替换为具体的文件路径。
使用示例

假设您有一个名为 NIMSDK.framework 的 framework,并且它位于 /path/to/~/NIMSDK.framework 路径,那么您可以按照以下方式处理:

1.通过 cd 命令进入到 NIMSDK.framework 的路径。
如果是通过 pod install 获取的 SDK,则进入 pods 文件夹。
2.执行以下命令检查 framework 是否包d
含 bitcode,返回 0 即为不包含。

otool -l NIMSDK | grep __LLVM | wc -l

3.如果检测结果不是 0,则继续执行以下命令移除 NIMSDK.framework 的 Bitcode。

xcrun bitcode_strip -r NIMSDK -o NIMSDK
上一篇 下一篇

猜你喜欢

热点阅读