我在我的电容器应用程序中使用一个小部件(目前这个问题仅关注 iOS)。
我想将 webview 代码中的整数保存到首选项中,然后能够从 iOS 小部件中读取它。
也许我也可以使用 SQLite 来实现此目的,如下所示: https://forum.ionicframework.com/t/will-app-clips-be-available-in-ionic/194768/10?u=folsze
但我认为我仍然需要使用应用程序组,即使对于 sqlite,这也会使电容器的写入过程变得复杂?还是我错了?
这有可能吗?还是我正在尝试完成一些不可能的事情? (iOS 和 Android 都不能实现吗?)。我特别怀疑我的 webview 代码的写入是否能够写入特定组,因为我不确定 Preferences.ConfigureOptions.group 是否引用与 iOS 应用程序扩展组相同的概念
我在 Xcode 中为我的本机应用程序和本机小部件创建了一个组,具有相同的名称:
我尝试使用configureoptions组来做到这一点,但整数永远不会到达小部件,它不存在:
https://capacitorjs.com/docs/apis/preferences#configureoptions
这是我的网络视图代码:
const key = 'widgetStreak';
const value = String(this.streak);
console.log("AAA", key, value);
await Preferences.configure({group: "group.com.company.name"});
await Preferences.set({ key, value });
这是我的小部件代码:
import WidgetKit
import SwiftUI
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), streak: 0)
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), streak: fetchStreak())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate, streak: fetchStreak())
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
private func fetchStreak() -> Int {
guard let userDefaults = UserDefaults(suiteName: "group.com.company.name") else {
print("Failed to initialize UserDefaults.")
return 0
}
// Ensure that UserDefaults are synchronized
userDefaults.synchronize()
// Check if the key exists
if userDefaults.object(forKey: "widgetStreak") == nil {
print("Key 'widgetStreak' does not exist.")
return 0
}
let ret = userDefaults.integer(forKey: "widgetStreak")
if ret == 0 {
print("The value for 'widgetStreak' is zero.")
} else {
print("The value for 'widgetStreak' is: \(ret)")
}
return ret
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let streak: Int
}
struct TestWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
Text("Daily Streak")
Text("\(entry.streak) days")
.font(.largeTitle)
}
}
}
struct TestWidget: Widget {
let kind: String = "TestWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
if #available(iOS 17.0, *) {
TestWidgetEntryView(entry: entry)
.containerBackground(.fill.tertiary, for: .widget)
} else {
TestWidgetEntryView(entry: entry)
.padding()
.background()
}
}
.configurationDisplayName("Daily Streak Widget")
.description("Displays your daily streak.")
}
}
#Preview(as: .systemSmall) {
TestWidget()
} timeline: {
SimpleEntry(date: .now, streak: 0)
SimpleEntry(date: .now, streak: 5)
}
这是我从本机小部件代码获得的输出:
Couldn't read values in CFPrefsPlistSource<0x101c854a0> (Domain: group.com.felixolszewski.geochamp1, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd
Key 'widgetStreak' does not exist.
Key 'widgetStreak' does not exist.
Key 'widgetStreak' does not exist.
Key 'widgetStreak' does not exist.
Key 'widgetStreak' does not exist.
Key 'widgetStreak' does not exist.
Key 'widgetStreak' does not exist.
Key 'widgetStreak' does not exist.
Key 'widgetStreak' does not exist.
Key 'widgetStreak' does not exist.
显然这个警告可以忽略: https://stackoverflow.com/a/39923879/20009330
我还尝试了这篇文章中的所有建议: 无法读取 CFPrefsPlistSource iOS 10 中的值
但是没有任何帮助,仍然得到
Key 'widgetStreak' does not exist.
,这让我认为这对于电容器来说是不可能的。也许有人可以建议一些替代的解决方法?也许可以从小部件访问 webview localStorage?我在这里找到了一些线索,无论出于何种原因,localStorage 或 indexedDB 都不是一个好的选择:
https://forum.ionicframework.com/t/will-app-clips-be-available-in-ionic/194768/10?u=folsze
不要让 JS 写入数字,而是让 JS 将数字传递给 iOS 端写入数字的插件。我最近已经做到了这一点,并从 Capacitor 的文档中学到了我需要的一切
https://capacitorjs.com/docs/plugins/ios
基本轮廓是
然后您需要使用 Xcode 的应用程序组来确保 App 和 Widget 都可以读取相同的文件