diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccdbede..c2dd59a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,4 +14,6 @@ permissions: jobs: call-workflow: uses: skiptools/actions/.github/workflows/skip-framework.yml@v1 - + with: + runs-on: "['macos-15-intel', 'ubuntu-24.04']" + swift-android-sdk-version: "['', 'nightly-main']" diff --git a/Package.swift b/Package.swift index 349eeb8..933da08 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.9 +// swift-tools-version: 6.1 import PackageDescription let package = Package( diff --git a/Sources/SkipAndroidBridge/AndroidBridgeBootstrap.swift b/Sources/SkipAndroidBridge/AndroidBridgeBootstrap.swift index 5292554..fcba764 100644 --- a/Sources/SkipAndroidBridge/AndroidBridgeBootstrap.swift +++ b/Sources/SkipAndroidBridge/AndroidBridgeBootstrap.swift @@ -64,7 +64,7 @@ public class AndroidBridge { /// get `Foundation` idioms working with Android conventions. // SKIP @bridge public class AndroidBridgeBootstrap { - private static var androidBridgeInit = false + nonisolated(unsafe) private static var androidBridgeInit = false /// Perform all the setup that is needed to get `Foundation` idioms working with Android conventions. /// diff --git a/Sources/SkipAndroidBridge/AndroidBundle.swift b/Sources/SkipAndroidBridge/AndroidBundle.swift index 09719f5..67827b2 100644 --- a/Sources/SkipAndroidBridge/AndroidBundle.swift +++ b/Sources/SkipAndroidBridge/AndroidBundle.swift @@ -50,16 +50,19 @@ open class AndroidBundle : Foundation.Bundle, @unchecked Sendable { super.init(path: Foundation.Bundle.main.bundlePath)! } - // These inits require 'override' on Android but not iOS or ROBOLECTRIC + // These inits require 'override' on Android but not iOS or ROBOLECTRIC. + // They must not be marked unavailable because the auto-generated + // resource_bundle_accessor.swift (produced by the swiftbuild build system) + // calls Bundle(for: BundleFinder.self) as part of its fallback chain. #if os(Android) - @available(*, unavailable) public override init(for aClass: AnyClass) { - fatalError() + self.bundleAccess = BundleAccess.main + super.init(path: Foundation.Bundle.main.bundlePath)! } - @available(*, unavailable) public override init?(identifier: String) { - fatalError() + self.bundleAccess = BundleAccess.main + super.init(path: Foundation.Bundle.main.bundlePath)! } #endif diff --git a/Sources/SkipAndroidBridge/AndroidUserDefaults.swift b/Sources/SkipAndroidBridge/AndroidUserDefaults.swift index c015d39..9a0043c 100644 --- a/Sources/SkipAndroidBridge/AndroidUserDefaults.swift +++ b/Sources/SkipAndroidBridge/AndroidUserDefaults.swift @@ -7,7 +7,7 @@ open class AndroidUserDefaults : Foundation.UserDefaults { open override class var standard: AndroidUserDefaults { return _standard } - private static let _standard = AndroidUserDefaults() + nonisolated(unsafe) private static let _standard = AndroidUserDefaults() private let userDefaultsAccess: UserDefaultsAccess diff --git a/Sources/SkipAndroidBridge/AssetURLProtocol.swift b/Sources/SkipAndroidBridge/AssetURLProtocol.swift index e011130..4b64a52 100644 --- a/Sources/SkipAndroidBridge/AssetURLProtocol.swift +++ b/Sources/SkipAndroidBridge/AssetURLProtocol.swift @@ -11,10 +11,10 @@ fileprivate let logger: Logger = Logger(subsystem: "skip.android.bridge", catego /// A custom URLProtocol that serves requests from the native Android `AAssetManager`, which is implemented in `swift-android-native / AndroidAssetManager.swift` public class AssetURLProtocol: URLProtocol { /// The URL scheme that this protocol handles - public static var scheme = "asset" + public static let scheme = "asset" - private static var registered = false - private static var assetManager: AndroidAssetManager? = nil + nonisolated(unsafe) private static var registered = false + nonisolated(unsafe) private static var assetManager: AndroidAssetManager? = nil public static func register() throws { if registered { return } diff --git a/Tests/SkipAndroidBridgeSamplesTests/SkipAndroidBridgeSamplesTests.swift b/Tests/SkipAndroidBridgeSamplesTests/SkipAndroidBridgeSamplesTests.swift index 4594dcb..0ed27fb 100644 --- a/Tests/SkipAndroidBridgeSamplesTests/SkipAndroidBridgeSamplesTests.swift +++ b/Tests/SkipAndroidBridgeSamplesTests/SkipAndroidBridgeSamplesTests.swift @@ -99,7 +99,7 @@ final class SkipAndroidBridgeSamplesTests: XCTestCase { } // SkipAndroidBridgeSamplesTests.kt testAndroidContext -> SkipAndroidBridgeSamples.kt nativeAndroidContextPackageName -> SkipAndroidBridgeSamples.swift nativeAndroidContextPackageName -> AndroidContext.swift getPackageName() - XCTAssertEqual("skip.android.bridge.samples.test", try nativeAndroidContextPackageName()) + XCTAssertEqual("skip.android.bridge.samples.module.test", try nativeAndroidContextPackageName()) } func testLocalizedStringResource() throws { diff --git a/Tests/SkipAndroidBridgeTests/AndroidBridgeTests.swift b/Tests/SkipAndroidBridgeTests/AndroidBridgeTests.swift index 81285f5..43d7d87 100644 --- a/Tests/SkipAndroidBridgeTests/AndroidBridgeTests.swift +++ b/Tests/SkipAndroidBridgeTests/AndroidBridgeTests.swift @@ -29,13 +29,13 @@ final class AndroidBridgeTests: XCTestCase { let cacheDir = URL(fileURLWithPath: context.getCacheDir().getAbsolutePath(), isDirectory: true) if isRobolectric { - // Robolectric's files folder is tough to predict (e.g. /var/folders/zl/wkdjv4s1271fbm6w0plzknkh0000gn/T/robolectric-AndroidBridgeTests_testAndroidBridge_SkipAndroidBridge_debugUnitTest10131350412654065418/skip.android.bridge.test-dataDir/files) - XCTAssertTrue(filesDir.path.hasSuffix("/files"), "unexpected filesDir.path: \(filesDir.path)") - XCTAssertTrue(cacheDir.path.hasSuffix("/cache"), "unexpected cacheDir.path: \(cacheDir.path)") + // Robolectric's files folder is tough to predict (e.g. /var/folders/zl/wkdjv4s1271fbm6w0plzknkh0000gn/T/robolectric-AndroidBridgeTests_testAndroidBridge_SkipAndroidBridge_debugUnitTest10131350412654065418/skip.android.bridge.module.test-dataDir/files) + XCTAssertTrue(filesDir.path.hasSuffix("/skip.android.bridge.module.test-dataDir/files"), "unexpected filesDir.path: \(filesDir.path)") + XCTAssertTrue(cacheDir.path.hasSuffix("/skip.android.bridge.module.test-dataDir/cache"), "unexpected cacheDir.path: \(cacheDir.path)") } else { // …but Android is predictably the app's "files" and "cache" directories - XCTAssertEqual("/data/user/0/skip.android.bridge.test/files", filesDir.path) - XCTAssertEqual("/data/user/0/skip.android.bridge.test/cache", cacheDir.path) + XCTAssertEqual("/data/user/0/skip.android.bridge.module.test/files", filesDir.path) + XCTAssertEqual("/data/user/0/skip.android.bridge.module.test/cache", cacheDir.path) } // make sure we can read and write to the filesDir