Swift中如何从Widget小组件包内的JSON文件读取数据?
报错原因
Bundle.main读取的是主App的资源包,Widget Extension是独立的扩展target,资源默认打包在专属的Widget bundle中,和主App资源包隔离,因此无法直接通过主包找到json文件。
解决步骤
配置文件成员资格
选中Xcode项目导航栏中的cars.json文件,打开右侧「文件检查器(File Inspector)」面板,在「Target Membership」区域勾选Widget Extension对应的target(如果主App也需要用到该文件,可以同时勾选主App target),保证文件会被打包进Widget的资源包。修改资源读取代码
不要硬编码使用Bundle.main,改为明确传入Widget对应的bundle,同时拆分文件名和后缀减少匹配错误,优化后的代码示例如下:
// 通用解析方法增加bundle参数,默认兼容主App调用 func load<T: Decodable>(_ filename: String, suffix: String = "json", bundle: Bundle = .main) -> T { let data: Data guard let file = bundle.url(forResource: filename, withExtension: suffix) else { fatalError("Couldn't find \(filename).\(suffix) in \(bundle) bundle.") } do { data = try Data(contentsOf: file) } catch { fatalError("Couldn't load \(filename).\(suffix) from \(bundle) bundle:\n\(error)") } do { let decoder = JSONDecoder() return try decoder.decode(T.self, from: data) } catch { fatalError("Couldn't parse \(filename).\(suffix) as \(T.self):\n\(error)") } } // Widget中调用时传入Widget对应的bundle,替换为你自己的Widget Extension的Bundle ID guard let widgetBundle = Bundle(identifier: "com.your.team.widget.bundle.id") else { fatalError("Can not find widget bundle") } var weeks: [CarTypes] = load("cars", bundle: widgetBundle)
Widget的Bundle ID可以在Xcode的TARGETS列表中选中Widget Extension,在「Signing & Capabilities」页面查看。
异常排查
如果配置后仍然报错,可以做如下校验:
- 确认文件名大小写完全匹配,iOS文件系统大小写敏感,
Cars.json和cars.json会被识别为不同文件 - 编译成功后右键点击Xcode产物栏的.app文件,选择「显示包内容」,进入
Plugins目录下的Widget扩展包,确认cars.json存在于资源目录中
内容的提问来源于stack exchange,提问作者Danny Yuan
相关产品推荐
相关产品推荐

