Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"expo": {
"name": "모아동",
"slug": "moadong-app",
"version": "1.7.2",
"version": "1.7.3",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "moadongapp",
"userInterfaceStyle": "light",
"newArchEnabled": true,
"ios": {
"supportsTablet": false,
"buildNumber": "19",
"buildNumber": "20",
"googleServicesFile": "./GoogleService-Info.plist",
"bundleIdentifier": "com.moadong.moadong",
"associatedDomains": [
Expand All @@ -26,7 +26,7 @@
},
"android": {
"jsEngine": "hermes",
"versionCode": 19,
"versionCode": 20,
"adaptiveIcon": {
"backgroundColor": "#E6F4FE",
"foregroundImage": "./assets/images/android-icon-foreground.png",
Expand Down
12 changes: 8 additions & 4 deletions ios/app.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
82AA7221D96D78101B265EA1 /* Pods_app.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A2FE34E4E96E79AB979AE79F /* Pods_app.framework */; };
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748412D0307B40044C1D9 /* AppDelegate.swift */; };
F1A5CE0D2EA0000000000002 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1A5CE0D2EA0000000000001 /* SceneDelegate.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -31,6 +32,7 @@
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
F11748412D0307B40044C1D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = app/AppDelegate.swift; sourceTree = "<group>"; };
F11748442D0722820044C1D9 /* app-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "app-Bridging-Header.h"; path = "app/app-Bridging-Header.h"; sourceTree = "<group>"; };
F1A5CE0D2EA0000000000001 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SceneDelegate.swift; path = app/SceneDelegate.swift; sourceTree = "<group>"; };
FFC3E90B83FE5881E7191A28 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = app/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand All @@ -50,6 +52,7 @@
isa = PBXGroup;
children = (
F11748412D0307B40044C1D9 /* AppDelegate.swift */,
F1A5CE0D2EA0000000000001 /* SceneDelegate.swift */,
F11748442D0722820044C1D9 /* app-Bridging-Header.h */,
BB2F792B24A3F905000567C9 /* Supporting */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
Expand Down Expand Up @@ -403,6 +406,7 @@
buildActionMask = 2147483647;
files = (
F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */,
F1A5CE0D2EA0000000000002 /* SceneDelegate.swift in Sources */,
4EB67CDF4FA2FA6DB261C2AF /* ExpoModulesProvider.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -417,7 +421,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = app/app.entitlements;
CURRENT_PROJECT_VERSION = 19;
CURRENT_PROJECT_VERSION = 20;
DEVELOPMENT_TEAM = 2QMK9GBWN6;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
Expand All @@ -430,7 +434,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.7.2;
MARKETING_VERSION = 1.7.3;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand All @@ -454,15 +458,15 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = app/app.entitlements;
CURRENT_PROJECT_VERSION = 19;
CURRENT_PROJECT_VERSION = 20;
DEVELOPMENT_TEAM = 2QMK9GBWN6;
INFOPLIST_FILE = app/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.7.2;
MARKETING_VERSION = 1.7.3;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down
21 changes: 19 additions & 2 deletions ios/app/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.7.2</string>
<string>1.7.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand All @@ -39,7 +39,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>19</string>
<string>20</string>
<key>LSMinimumSystemVersion</key>
<string>12.0</string>
<key>LSRequiresIPhoneOS</key>
Expand All @@ -59,6 +59,23 @@
<string>동아리 지원 시 입력한 이름과 전화번호를 동아리 관리자에게 전달하는 용도로만 사용됩니다.</string>
<key>RCTNewArchEnabled</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>UILaunchStoryboardName</key>
<string>SplashScreen</string>
<key>UIRequiredDeviceCapabilities</key>
Expand Down
53 changes: 53 additions & 0 deletions ios/app/SceneDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import UIKit

// iOS 27 SDK부터 UIScene 생명주기가 필수라 추가한 얇은 어댑터.
// React Native는 AppDelegate가 띄운 window를 그대로 쓰고, URL 진입은 AppDelegate로 위임해
// firebaseauth 필터 → Expo 구독자(expo-linking, expo-router) → RCTLinkingManager 순서를 유지한다.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?

func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard
let windowScene = scene as? UIWindowScene,
let appWindow = (UIApplication.shared.delegate as? AppDelegate)?.window
else {
return
}

appWindow.windowScene = windowScene
appWindow.makeKeyAndVisible()
window = appWindow

// Scene 생명주기에서는 cold start URL이 launchOptions가 아니라 connectionOptions로 들어온다.
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
for userActivity in connectionOptions.userActivities {
self.scene(scene, continue: userActivity)
}
}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}

for context in URLContexts {
var options: [UIApplication.OpenURLOptionsKey: Any] = [:]
if let sourceApplication = context.options.sourceApplication {
options[.sourceApplication] = sourceApplication
}
_ = appDelegate.application(UIApplication.shared, open: context.url, options: options)
}
}

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}

_ = appDelegate.application(UIApplication.shared, continue: userActivity, restorationHandler: { _ in })
}
}
53 changes: 53 additions & 0 deletions plugins/ios-prebuild-support/SceneDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import UIKit

// iOS 27 SDK부터 UIScene 생명주기가 필수라 추가한 얇은 어댑터.
// React Native는 AppDelegate가 띄운 window를 그대로 쓰고, URL 진입은 AppDelegate로 위임해
// firebaseauth 필터 → Expo 구독자(expo-linking, expo-router) → RCTLinkingManager 순서를 유지한다.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?

func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard
let windowScene = scene as? UIWindowScene,
let appWindow = (UIApplication.shared.delegate as? AppDelegate)?.window
else {
return
}

appWindow.windowScene = windowScene
appWindow.makeKeyAndVisible()
window = appWindow

// Scene 생명주기에서는 cold start URL이 launchOptions가 아니라 connectionOptions로 들어온다.
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
for userActivity in connectionOptions.userActivities {
self.scene(scene, continue: userActivity)
}
}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}

for context in URLContexts {
var options: [UIApplication.OpenURLOptionsKey: Any] = [:]
if let sourceApplication = context.options.sourceApplication {
options[.sourceApplication] = sourceApplication
}
_ = appDelegate.application(UIApplication.shared, open: context.url, options: options)
}
}

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}

_ = appDelegate.application(UIApplication.shared, continue: userActivity, restorationHandler: { _ in })
}
}
35 changes: 30 additions & 5 deletions plugins/withIosPrebuildFixes.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
const fs = require('fs');
const path = require('path');
const { withFinalizedMod, withPodfile, withXcodeProject } = require('@expo/config-plugins');
const { IOSConfig, withFinalizedMod, withInfoPlist, withPodfile, withXcodeProject } = require('@expo/config-plugins');

const SUPPORT_DIR = path.join(__dirname, 'ios-prebuild-support');

// iOS 27 SDK부터 UIScene 생명주기가 필수다. SceneDelegate는 AppDelegate의 window와 URL 처리를 그대로 재사용한다.
const SCENE_DELEGATE_FILE = 'SceneDelegate.swift';
const SCENE_MANIFEST = {
UIApplicationSupportsMultipleScenes: false,
UISceneConfigurations: {
UIWindowSceneSessionRoleApplication: [
{
UISceneConfigurationName: 'Default Configuration',
UISceneDelegateClassName: '$(PRODUCT_MODULE_NAME).SceneDelegate',
},
],
},
};

const RNFB_SCRIPT_PHASE_NAMES = new Set([
'[CP-User] [RNFB] Core Configuration',
'[CP-User] [RNFB] Crashlytics Configuration',
Expand Down Expand Up @@ -143,7 +157,12 @@ function normalizeXcodeString(value) {
.replace(/\\"/g, '"');
}

function applyXcodeProjectFixes(project) {
function applyXcodeProjectFixes(project, projectName) {
const sceneDelegatePath = `${projectName}/${SCENE_DELEGATE_FILE}`;
if (!project.hasFile(sceneDelegatePath)) {
IOSConfig.XcodeUtils.addBuildSourceFileToGroup({ filepath: sceneDelegatePath, groupName: projectName, project });
}

const shellScriptBuildPhases = project.hash?.project?.objects?.PBXShellScriptBuildPhase;

for (const phase of Object.values(shellScriptBuildPhases || {})) {
Expand Down Expand Up @@ -179,7 +198,8 @@ function removeAppTestsFromScheme(schemeContents) {
});
}

function applyFinalizedFileFixes(platformProjectRoot) {
function applyFinalizedFileFixes(platformProjectRoot, projectName) {
copySupportFile(SCENE_DELEGATE_FILE, path.join(platformProjectRoot, projectName, SCENE_DELEGATE_FILE));
copySupportFile('xcode.env', path.join(platformProjectRoot, '.xcode.env'));
copySupportFile('ci_post_clone.sh', path.join(platformProjectRoot, 'ci_scripts', 'ci_post_clone.sh'), 0o755);
copySupportFile(
Expand All @@ -200,15 +220,20 @@ module.exports = function withIosPrebuildFixes(config) {
return config;
});

config = withInfoPlist(config, (config) => {
config.modResults.UIApplicationSceneManifest = SCENE_MANIFEST;
return config;
});

config = withXcodeProject(config, (config) => {
config.modResults = applyXcodeProjectFixes(config.modResults);
config.modResults = applyXcodeProjectFixes(config.modResults, config.modRequest.projectName);
return config;
});

return withFinalizedMod(config, [
'ios',
(config) => {
applyFinalizedFileFixes(config.modRequest.platformProjectRoot);
applyFinalizedFileFixes(config.modRequest.platformProjectRoot, config.modRequest.projectName);
return config;
},
]);
Expand Down
Loading