Skip to content

Commit 65f99ef

Browse files
feat: add Swift Package Manager support and upgrade to Expo SDK 56 (#11)
1 parent 68fa959 commit 65f99ef

39 files changed

Lines changed: 7764 additions & 11031 deletions

.eslintrc.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@ yarn-error.log
3939

4040
# Expo
4141
.expo/*
42+
43+
# Swift Package Manager
44+
#
45+
.build/
46+
.swiftpm/
47+
Package.resolved

Package.swift

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// swift-tools-version:5.9
2+
//
3+
// This Package.swift is forward-compatibility scaffolding for the React Native
4+
// SPM migration outlined in RFC 0994:
5+
// https://github.com/react-native-community/discussions-and-proposals/pull/994
6+
//
7+
// The RN CLI's SPM autolinking (and Expo's `et prebuild` pipeline that consumes
8+
// `spm.config.json`) is the supported install path. The expo-modules-core
9+
// dependency below points at the standard React Native / Expo `node_modules`
10+
// layout (`../expo-modules-core` relative to this package). That matches the
11+
// shape RFC 0994's autolinking generates and works whenever this package is
12+
// resolved as a local SPM package alongside a node_modules tree.
13+
//
14+
// As a consequence, this manifest does NOT resolve standalone via Xcode's
15+
// "Add Package Dependencies…" flow today — `../expo-modules-core` only
16+
// exists when the package is checked out beside an installed `node_modules/`.
17+
// That changes once Expo / RN ship a published `ExpoModulesCore` SPM product.
18+
//
19+
// Platform floor is iOS 14: that is when `NWBrowser` / local network
20+
// permission first exist. Bumping it would be an unnecessary breaking change
21+
// for downstream apps still on the CocoaPods path.
22+
23+
import PackageDescription
24+
25+
let package = Package(
26+
name: "ReactNativeLocalNetworkPermission",
27+
platforms: [
28+
.iOS(.v14)
29+
],
30+
products: [
31+
.library(
32+
name: "ReactNativeLocalNetworkPermission",
33+
targets: ["ReactNativeLocalNetworkPermission"]
34+
)
35+
],
36+
dependencies: [
37+
// ⚠️ This relative path assumes a non-hoisted `node_modules/` layout where
38+
// this package lives one level deep (e.g. `node_modules/<pkg>/Package.swift`)
39+
// and `expo-modules-core` is a sibling. Hoisted monorepo layouts (Yarn
40+
// workspaces, pnpm) where `expo-modules-core` resolves elsewhere will fail
41+
// to resolve this dependency. The supported install path is RN/Expo's SPM
42+
// autolinking, not standalone `swift package` resolution.
43+
.package(name: "expo-modules-core", path: "../expo-modules-core")
44+
],
45+
targets: [
46+
.target(
47+
name: "ReactNativeLocalNetworkPermission",
48+
dependencies: [
49+
.product(name: "ExpoModulesCore", package: "expo-modules-core")
50+
],
51+
path: "ios",
52+
exclude: [
53+
"ReactNativeLocalNetworkPermission.podspec"
54+
],
55+
sources: [
56+
"ReactNativeLocalNetworkPermissionModule.swift",
57+
"LocalNetworkAuthorization.swift"
58+
],
59+
resources: [
60+
.copy("PrivacyInfo.xcprivacy")
61+
],
62+
linkerSettings: [
63+
.linkedFramework("Network")
64+
]
65+
)
66+
]
67+
)

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ Add this library to your project:
1111

1212
`yarn add @generac/react-native-local-network-permission`
1313

14+
### Swift Package Manager support
15+
16+
CocoaPods (via the bundled `.podspec`) is still the primary install path and works for every React Native and Expo app today.
17+
18+
This module also ships SPM scaffolding for the migration described in [React Native RFC 0994](https://github.com/react-native-community/discussions-and-proposals/pull/994) (CocoaPods deprecation, December 2026):
19+
20+
- `spm.config.json` — consumed by Expo's `et prebuild` pipeline (`EXPO_USE_PRECOMPILED_MODULES=1`) to generate XCFrameworks. Picked up automatically by Expo's autolinking; no extra setup.
21+
- `Package.swift` — a forward-compatible manifest. The library target declares its dependency on `ExpoModulesCore` by name; the consumer's autolinking pipeline (RN CLI's SPM autolinking once it lands, or a hand-written brownfield manifest) is responsible for providing `.package(path: ".../node_modules/expo-modules-core")`. As a result, this `Package.swift` does not resolve standalone via "Add Package Dependencies…" in Xcode today — that workflow becomes available once the React Native SPM autolinking proposal lands.
22+
1423
### iOS manual configuration
1524

1625
#### NSLocalNetworkUsageDescription

eslint.config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// @generated by expo-module-scripts
2+
const { defineConfig } = require('eslint/config');
3+
const baseConfig = require('expo-module-scripts/eslint.config.base');
4+
5+
module.exports = defineConfig([
6+
baseConfig,
7+
{
8+
ignores: ['build/**', 'example/**'],
9+
},
10+
]);

example/app.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@
66
"orientation": "portrait",
77
"icon": "./assets/icon.png",
88
"userInterfaceStyle": "light",
9+
"newArchEnabled": true,
910
"splash": {
1011
"image": "./assets/splash.png",
1112
"resizeMode": "contain",
1213
"backgroundColor": "#ffffff"
1314
},
1415
"ios": {
1516
"supportsTablet": true,
16-
"bundleIdentifier": "expo.modules.localnetworkpermission.example"
17+
"bundleIdentifier": "expo.modules.localnetworkpermission.example",
18+
"deploymentTarget": "16.4",
19+
"infoPlist": {
20+
"NSLocalNetworkUsageDescription": "This example app demonstrates requesting local network permission."
21+
}
1722
}
1823
}
1924
}

example/ios/Podfile

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,47 @@
1+
# Generated by `expo prebuild` — Expo SDK 56. Do not hand-edit; regenerate via prebuild.
12
require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
23
require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
34

45
require 'json'
56
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
67

7-
ENV['RCT_NEW_ARCH_ENABLED'] = podfile_properties['newArchEnabled'] == 'true' ? '1' : '0'
8-
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
8+
def ccache_enabled?(podfile_properties)
9+
# Environment variable takes precedence
10+
return ENV['USE_CCACHE'] == '1' if ENV['USE_CCACHE']
911

10-
platform :ios, podfile_properties['ios.deploymentTarget'] || '13.4'
11-
install! 'cocoapods',
12-
:deterministic_uuids => false
12+
# Fall back to Podfile properties
13+
podfile_properties['apple.ccacheEnabled'] == 'true'
14+
end
15+
16+
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
17+
ENV['RCT_USE_RN_DEP'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1'
18+
ENV['RCT_USE_PREBUILT_RNCORE'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1'
19+
ENV['RCT_HERMES_V1_ENABLED'] ||= '1' if podfile_properties['expo.useHermesV1'] == 'true'
20+
ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] != 'false'
21+
platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4'
1322

1423
prepare_react_native_project!
1524

1625
target 'reactnativelocalnetworkpermissionexample' do
1726
use_expo_modules!
18-
config = use_native_modules!
27+
28+
if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
29+
config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
30+
else
31+
config_command = [
32+
'node',
33+
'--no-warnings',
34+
'--eval',
35+
'require(\'expo/bin/autolinking\')',
36+
'expo-modules-autolinking',
37+
'react-native-config',
38+
'--json',
39+
'--platform',
40+
'ios'
41+
]
42+
end
43+
44+
config = use_native_modules!(config_command)
1945

2046
use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
2147
use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
@@ -33,26 +59,7 @@ target 'reactnativelocalnetworkpermissionexample' do
3359
installer,
3460
config[:reactNativePath],
3561
:mac_catalyst_enabled => false,
36-
:ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true',
62+
:ccache_enabled => ccache_enabled?(podfile_properties),
3763
)
38-
39-
# This is necessary for Xcode 14, because it signs resource bundles by default
40-
# when building for devices.
41-
installer.target_installation_results.pod_target_installation_results
42-
.each do |pod_name, target_installation_result|
43-
target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
44-
resource_bundle_target.build_configurations.each do |config|
45-
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
46-
end
47-
end
48-
end
49-
end
50-
51-
post_integrate do |installer|
52-
begin
53-
expo_patch_react_imports!(installer)
54-
rescue => e
55-
Pod::UI.warn e
56-
end
5764
end
5865
end

0 commit comments

Comments
 (0)