fix(native): add podspec to sofa-widgets-support module to resolve CocoaPods module map build failure

This commit is contained in:
2026-03-22 18:40:36 -04:00
parent f2f5e823f4
commit 91ca6ab3c0
8 changed files with 36 additions and 13 deletions
@@ -0,0 +1,6 @@
{
"platforms": ["ios"],
"ios": {
"modules": ["SofaWidgetsSupportModule"]
}
}
@@ -0,0 +1,20 @@
import { Platform } from "react-native";
function getModule() {
return require("./src/SofaWidgetsSupportModule").default;
}
export async function downloadWidgetImage(url: string, key: string): Promise<string | null> {
if (Platform.OS !== "ios") return null;
return getModule().downloadWidgetImage(url, key);
}
export async function copyBundledAsset(assetName: string, key: string): Promise<string | null> {
if (Platform.OS !== "ios") return null;
return getModule().copyBundledAsset(assetName, key);
}
export async function clearWidgetImages(): Promise<void> {
if (Platform.OS !== "ios") return;
return getModule().clearWidgetImages();
}
@@ -0,0 +1,23 @@
Pod::Spec.new do |s|
s.name = 'SofaWidgetsSupport'
s.version = '1.0.0'
s.summary = 'Native helpers for Sofa iOS widgets'
s.description = 'Image downloading and caching for Sofa widget extensions'
s.author = ''
s.homepage = 'https://docs.expo.dev/modules/'
s.platforms = {
:ios => '15.1',
:tvos => '15.1'
}
s.source = { git: '' }
s.static_framework = true
s.dependency 'ExpoModulesCore'
# Swift/Objective-C compatibility
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
}
s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
end
@@ -0,0 +1,113 @@
import ExpoModulesCore
import UIKit
private let groupIdentifier = "group.com.jakejarvis.sofa"
private let imageDirectory = "widget_images"
public class SofaWidgetsSupportModule: Module {
public func definition() -> ModuleDefinition {
Name("SofaWidgetsSupport")
AsyncFunction("downloadWidgetImage") { (url: String, key: String) -> String? in
guard let imageUrl = URL(string: url) else {
return nil
}
guard let directoryUrl = self.ensureImageDirectory() else {
return nil
}
let destinationUrl = directoryUrl.appendingPathComponent(key)
let (data, response) = try await URLSession.shared.data(from: imageUrl)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200
else {
return nil
}
guard let image = UIImage(data: data) else {
return nil
}
// Resize to fit widget dimensions (systemSmall ~155pt = ~465px at 3x)
let maxDimension: CGFloat = 465
let resized = resizeImage(image, maxDimension: maxDimension)
guard let jpegData = resized.jpegData(compressionQuality: 0.7) else {
return nil
}
try jpegData.write(to: destinationUrl, options: .atomic)
return destinationUrl.absoluteString
}
AsyncFunction("copyBundledAsset") { (assetName: String, key: String) -> String? in
guard let directoryUrl = self.ensureImageDirectory() else {
return nil
}
let destinationUrl = directoryUrl.appendingPathComponent(key)
// Skip if already copied
if FileManager.default.fileExists(atPath: destinationUrl.path) {
return destinationUrl.absoluteString
}
guard let image = UIImage(named: assetName) else {
return nil
}
guard let pngData = image.pngData() else {
return nil
}
try pngData.write(to: destinationUrl, options: .atomic)
return destinationUrl.absoluteString
}
AsyncFunction("clearWidgetImages") {
guard let containerUrl = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: groupIdentifier
) else {
return
}
let directoryUrl = containerUrl.appendingPathComponent(imageDirectory)
try? FileManager.default.removeItem(at: directoryUrl)
}
}
private func ensureImageDirectory() -> URL? {
guard let containerUrl = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: groupIdentifier
) else {
return nil
}
let directoryUrl = containerUrl.appendingPathComponent(imageDirectory)
try? FileManager.default.createDirectory(
at: directoryUrl,
withIntermediateDirectories: true
)
return directoryUrl
}
private func resizeImage(_ image: UIImage, maxDimension: CGFloat) -> UIImage {
let size = image.size
let scale = min(maxDimension / size.width, maxDimension / size.height, 1.0)
if scale >= 1.0 { return image }
let newSize = CGSize(
width: round(size.width * scale),
height: round(size.height * scale)
)
let renderer = UIGraphicsImageRenderer(size: newSize)
return renderer.image { _ in
image.draw(in: CGRect(origin: .zero, size: newSize))
}
}
}
@@ -0,0 +1,3 @@
import { requireNativeModule } from "expo";
export default requireNativeModule("SofaWidgetsSupport");