diff --git a/.github/workflows/ios.preview.firebase.yml b/.github/workflows/ios.preview.firebase.yml
new file mode 100644
index 000000000..1ea962c69
--- /dev/null
+++ b/.github/workflows/ios.preview.firebase.yml
@@ -0,0 +1,145 @@
+name: Notesnook iOS Preview
+
+on:
+ pull_request:
+ types: [opened, reopened, synchronize]
+ branches: [master, beta]
+ paths:
+ - "apps/mobile/**"
+ - "packages/**"
+ # re-run workflow if workflow file changes
+ - ".github/workflows/mobile.publish.firebase.yml"
+
+jobs:
+ build:
+ runs-on: macos-26
+ timeout-minutes: 60
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Setup Node
+ uses: ./.github/actions/setup-node-with-cache
+
+ - name: Setup Xcode
+ uses: maxim-lobanov/setup-xcode@v1
+ with:
+ xcode-version: "26.1.1"
+
+ - name: Install node modules
+ run: |
+ npm ci --ignore-scripts --prefer-offline --no-audit
+ npm run bootstrap -- --scope=mobile
+
+ - name: Build packages
+ run: npm run tx @notesnook/mobile:build
+
+ - name: Cache Pods
+ uses: actions/cache@v3
+ id: pods-cache
+ with:
+ path: apps/mobile/ios/Pods
+ key: ${{ runner.os }}-pods-${{ hashFiles('apps/mobile/ios/Podfile.lock') }}
+
+ - name: Install Pods
+ run: |
+ cd apps/mobile/ios
+ pod install
+
+ - name: Check for typescript errors
+ run: |
+ npm run tx mobile:build
+ cd apps/mobile
+ npx tsc --noEmit
+
+ - name: Get marketing version
+ id: marketing-version
+ run: echo "version=$(grep "IOS_MARKETING_VERSION" apps/mobile/ios/build-configs/ios-build.staging.xcconfig | awk -F'=' '{print $2}' | xargs)" >> $GITHUB_OUTPUT
+
+ - name: Get build number
+ id: build-number
+ run: echo "timestamp=$(($(date +%s) - 1774851180 ))" >> $GITHUB_OUTPUT
+
+ - name: Make staging xcconfig active
+ run: |
+ cd apps/mobile/ios/build-configs
+ ./use-ios-build-config.sh staging --marketing-version ${{steps.marketing-version.outputs.version}} --build-number ${{steps.build-number.outputs.timestamp}}
+
+ - name: Build iOS App
+ uses: ammarahm-ed/ios-build-action@master
+ with:
+ bundle-identifier: org.streetwriters.notesnook
+ scheme: Notesnook
+ configuration: "Release"
+ export-options: apps/mobile/ios/ExportOptionsStaging.plist
+ export-method: "ad-hoc"
+ project-path: apps/mobile/ios/Notesnook.xcodeproj
+ workspace-path: apps/mobile/ios/Notesnook.xcworkspace
+ update-targets: |
+ Notesnook
+ Make Note
+ NotesWidgetExtension
+ disable-targets: Notesnook-tvOS,Notesnook-tvOSTests,NotesnookTests
+ code-signing-identity: Apple Distribution
+ team-id: ${{ secrets.APPLE_TEAM_ID }}
+ p12-base64: ${{ secrets.APPLE_CERTIFICATE_P12 }}
+ certificate-password: ${{ secrets.APPLE_CERTIFICATE_P12_PASSWORD }}
+ app-store-connect-api-key-issuer-id: ${{ secrets.API_KEY_ISSUER_ID }}
+ app-store-connect-api-key-id: ${{ secrets.APPSTORE_KEY_ID }}
+ app-store-connect-api-key-base64: ${{ secrets.APPSTORE_CONNECT_API_KEY_BASE64 }}
+ output-path: Notesnook.ipa
+ mobileprovision-base64: |
+ ${{ secrets.APPLE_MOBILE_PROVISION_ADHOC_APP }}
+ ${{ secrets.APPLE_MOBILE_PROVISION_ADHOC_SHARE }}
+ ${{ secrets.APPLE_MOBILE_PROVISION_ADHOC_WIDGET }}
+
+ - name: Publish to firebase CLI
+ id: firebase-output
+ uses: wzieba/Firebase-Distribution-Github-Action@v1
+ with:
+ appId: ${{secrets.FIREBASE_IOS_APP_ID}}
+ serviceCredentialsFileContent: ${{ secrets.QA_SERVICE_ACCOUNT }}
+ groups: testers
+ file: Notesnook.ipa
+
+ - name: Post or update PR comment
+ uses: actions/github-script@v6
+ env:
+ preview_url: ${{ steps.firebase-output.outputs.TESTING_URI }}
+ with:
+ script: |
+ const marker = '';
+ const prNumber = context.issue.number;
+ const previewUrl = process.env.preview_url || '';
+ const body = `${marker}\n**iOS App Preview**\n\n${previewUrl || 'Preview URL unavailable — check workflow logs.'}\n\nCommit: ${process.env.GITHUB_SHA}\n`;
+ const { data: comments } = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: prNumber,
+ });
+ const existing = comments.find(c => c.body && c.body.includes(marker));
+ if (existing) {
+ await github.rest.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: existing.id,
+ body,
+ });
+ } else {
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: prNumber,
+ body,
+ });
+ }
+
+ # - name: Upload Notesnook.ipa to Github
+ # uses: actions/upload-artifact@v4
+ # with:
+ # name: Notesnook.zip
+ # path: |
+ # Notesnook.ipa
+ # apps/mobile/ios/**/*.map
+ # packages/editor-mobile/sourcemaps/*.map
diff --git a/apps/mobile/ios/ExportOptionsStaging.plist b/apps/mobile/ios/ExportOptionsStaging.plist
new file mode 100644
index 000000000..7aca51e30
--- /dev/null
+++ b/apps/mobile/ios/ExportOptionsStaging.plist
@@ -0,0 +1,15 @@
+
+
+
+
+ provisioningProfiles
+
+ org.streetwriters.notesnook
+ Notesnook Adhoc 2026
+ org.streetwriters.notesnook.notewidget
+ Notesnook Note Widget Adhoc 2026
+ org.streetwriters.notesnook.share
+ Notesnook Share Adhoc 2026
+
+
+
\ No newline at end of file
diff --git a/apps/mobile/ios/Notesnook.xcodeproj/project.pbxproj b/apps/mobile/ios/Notesnook.xcodeproj/project.pbxproj
index 7d26398c7..45261c8ae 100644
--- a/apps/mobile/ios/Notesnook.xcodeproj/project.pbxproj
+++ b/apps/mobile/ios/Notesnook.xcodeproj/project.pbxproj
@@ -144,6 +144,7 @@
65E03409257B9FF100793428 /* Notesnook-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Notesnook-Bridging-Header.h"; sourceTree = ""; };
65E0340A257B9FF100793428 /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; };
65EC5B71272A7EE200FB3748 /* NotesWidgetExtensionDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NotesWidgetExtensionDebug.entitlements; sourceTree = ""; };
+ 684AA0A1B1BE6091A02D42FF /* ios-build.active.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "ios-build.active.xcconfig"; path = "build-configs/ios-build.active.xcconfig"; sourceTree = SOURCE_ROOT; };
77124A1C1FB538ED63FDEF82 /* Pods-Notesnook.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Notesnook.release.xcconfig"; path = "Target Support Files/Pods-Notesnook/Pods-Notesnook.release.xcconfig"; sourceTree = ""; };
7D3F6A50D104CE391243515F /* Pods-Notesnook-Add to Notes.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Notesnook-Add to Notes.release.xcconfig"; path = "Target Support Files/Pods-Notesnook-Add to Notes/Pods-Notesnook-Add to Notes.release.xcconfig"; sourceTree = ""; };
88211800FA8BF60638327ADE /* Pods-Make Note.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Make Note.debug.xcconfig"; path = "Target Support Files/Pods-Make Note/Pods-Make Note.debug.xcconfig"; sourceTree = ""; };
@@ -312,6 +313,7 @@
2D16E6871FA4F8E400B85C8A /* Frameworks */,
DA84645424CFBF19A44D64B3 /* Pods */,
B5216B66C0B4A91C0A69128B /* PrivacyInfo.xcprivacy */,
+ 684AA0A1B1BE6091A02D42FF /* ios-build.active.xcconfig */,
);
indentWidth = 2;
sourceTree = "";
@@ -1035,7 +1037,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2178;
+ CURRENT_PROJECT_VERSION = "$(IOS_CURRENT_PROJECT_VERSION)";
DEVELOPMENT_TEAM = 53CWBG3QUC;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1110,13 +1112,13 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 3.3.18;
+ MARKETING_VERSION = "$(IOS_MARKETING_VERSION)";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
- PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook;
+ PRODUCT_BUNDLE_IDENTIFIER = "$(IOS_MAIN_BUNDLE_ID)";
PRODUCT_NAME = Notesnook;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Notesnook-Bridging-Header.h";
@@ -1141,7 +1143,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 2178;
+ CURRENT_PROJECT_VERSION = "$(IOS_CURRENT_PROJECT_VERSION)";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1216,17 +1218,17 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 3.3.18;
+ MARKETING_VERSION = "$(IOS_MARKETING_VERSION)";
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
- PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook;
+ PRODUCT_BUNDLE_IDENTIFIER = "$(IOS_MAIN_BUNDLE_ID)";
PRODUCT_NAME = Notesnook;
PROVISIONING_PROFILE_SPECIFIER = "";
- "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Notesnook 2026";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "$(IOS_MAIN_PROFILE)";
SWIFT_OBJC_BRIDGING_HEADER = "Notesnook-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -1373,7 +1375,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2178;
+ CURRENT_PROJECT_VERSION = "$(IOS_CURRENT_PROJECT_VERSION)";
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1385,10 +1387,10 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 3.3.18;
+ MARKETING_VERSION = "$(IOS_MARKETING_VERSION)";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
+ PRODUCT_BUNDLE_IDENTIFIER = "$(IOS_WIDGET_BUNDLE_ID)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
@@ -1416,7 +1418,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 2178;
+ CURRENT_PROJECT_VERSION = "$(IOS_CURRENT_PROJECT_VERSION)";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
@@ -1429,12 +1431,12 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 3.3.18;
+ MARKETING_VERSION = "$(IOS_MARKETING_VERSION)";
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
+ PRODUCT_BUNDLE_IDENTIFIER = "$(IOS_WIDGET_BUNDLE_ID)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
- "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Notesnook Note Widget 2026";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "$(IOS_WIDGET_PROFILE)";
SKIP_INSTALL = YES;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
@@ -1459,7 +1461,7 @@
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2178;
+ CURRENT_PROJECT_VERSION = "$(IOS_CURRENT_PROJECT_VERSION)";
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1540,10 +1542,10 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
- MARKETING_VERSION = 3.3.18;
+ MARKETING_VERSION = "$(IOS_MARKETING_VERSION)";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
+ PRODUCT_BUNDLE_IDENTIFIER = "$(IOS_SHARE_BUNDLE_ID)";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Make Note/Make Note-Bridging-Header.h";
@@ -1571,7 +1573,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 2178;
+ CURRENT_PROJECT_VERSION = "$(IOS_CURRENT_PROJECT_VERSION)";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
@@ -1653,12 +1655,12 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
- MARKETING_VERSION = 3.3.18;
+ MARKETING_VERSION = "$(IOS_MARKETING_VERSION)";
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
+ PRODUCT_BUNDLE_IDENTIFIER = "$(IOS_SHARE_BUNDLE_ID)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
- "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Notesnook Share 2026";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "$(IOS_SHARE_PROFILE)";
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Make Note/Make Note-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -1668,6 +1670,7 @@
};
83CBBA201A601CBA00E9B192 /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 684AA0A1B1BE6091A02D42FF /* ios-build.active.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
APPLICATION_EXTENSION_API_ONLY = YES;
@@ -1740,6 +1743,7 @@
};
83CBBA211A601CBA00E9B192 /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 684AA0A1B1BE6091A02D42FF /* ios-build.active.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
APPLICATION_EXTENSION_API_ONLY = YES;
diff --git a/apps/mobile/ios/Notesnook/Info.plist b/apps/mobile/ios/Notesnook/Info.plist
index 8ec6fb96e..38ddf54cf 100644
--- a/apps/mobile/ios/Notesnook/Info.plist
+++ b/apps/mobile/ios/Notesnook/Info.plist
@@ -12,7 +12,7 @@
CFBundleDevelopmentRegion
en
CFBundleDisplayName
- Notesnook
+ $(APP_DISPLAY_NAME)
CFBundleDocumentTypes
diff --git a/apps/mobile/ios/Podfile b/apps/mobile/ios/Podfile
index 69e14fe1c..5e28ff61a 100644
--- a/apps/mobile/ios/Podfile
+++ b/apps/mobile/ios/Podfile
@@ -86,4 +86,20 @@ post_install do |installer|
end
end
end
+
+ # Embed the active iOS build config xcconfig as the project-level base configuration.
+ # CocoaPods only manages target-level base configurations, so the project-level one
+ # is safe to set here and will survive future pod installs.
+ # To switch environments: update ios-build.active.xcconfig, then re-run pod install.
+ # active_xcconfig_rel_path = 'build-configs/ios-build.active.xcconfig'
+ # user_project = installer.aggregate_targets.first.user_project
+ # xcconfig_ref = user_project.files.find { |f| f.path&.end_with?('ios-build.active.xcconfig') }
+ # if xcconfig_ref.nil?
+ # xcconfig_ref = user_project.main_group.new_file(active_xcconfig_rel_path, :project)
+ # xcconfig_ref.last_known_file_type = 'text.xcconfig'
+ # end
+ # user_project.build_configurations.each do |config|
+ # config.base_configuration_reference = xcconfig_ref
+ # end
+ # user_project.save
end
diff --git a/apps/mobile/ios/Podfile.lock b/apps/mobile/ios/Podfile.lock
index 0fa6a3544..ad32c4ecf 100644
--- a/apps/mobile/ios/Podfile.lock
+++ b/apps/mobile/ios/Podfile.lock
@@ -2275,7 +2275,7 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- - react-native-upload (6.31.0):
+ - react-native-upload (6.33.0):
- React
- react-native-view-shot (4.0.3):
- boost
@@ -2872,7 +2872,7 @@ PODS:
- React-perflogger (= 0.82.1)
- React-utils (= 0.82.1)
- SocketRocket
- - RNBackgroundFetch (4.2.2):
+ - RNBackgroundFetch (4.2.3):
- React-Core
- RNBootSplash (6.3.11):
- boost
@@ -3092,10 +3092,10 @@ PODS:
- Yoga
- RNKeychain (4.0.5):
- React
- - RNNotifee (7.4.11):
+ - RNNotifee (7.4.12):
- React-Core
- - RNNotifee/NotifeeCore (= 7.4.11)
- - RNNotifee/NotifeeCore (7.4.11):
+ - RNNotifee/NotifeeCore (= 7.4.12)
+ - RNNotifee/NotifeeCore (7.4.12):
- React-Core
- RNPrivacySnapshot (1.0.0):
- React-Core
@@ -3875,19 +3875,19 @@ SPEC CHECKSUMS:
boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90
callstack-repack: 3991230773c74ea49e7db6932d20e72d175faa41
DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb
- fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6
+ fast_float: 914e00b8b67cb8ba184a778c7bbc2e9fe98d37b3
FBLazyVector: 0aa6183b9afe3c31fc65b5d1eeef1f3c19b63bfa
- fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
- glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
+ fmt: b85d977e8fe789fd71c77123f9f4920d88c4d170
+ glog: 682871fb30f4a65f657bf357581110656ea90b08
GZIP: 3c0abf794bfce8c7cb34ea05a1837752416c8868
- hermes-engine: 273e30e7fb618279934b0b95ffab60ecedb7acf5
+ hermes-engine: 1c85d2d2a4722541e6faffceb7bcc2249b5398b2
JWTDecode: 2eed97c2fa46ccaf3049a787004eedf0be474a87
MMKV: 7b5df6a8bf785c6705cc490c541b9d8a957c4a64
MMKVCore: 3f40b896e9ab522452df9df3ce983471aa2449ba
NitroCloudUploader: 62489381ed6b472d87c8c6b62629136ebd2342d1
NitroModules: f964d2f3f5b392d0c0303737085cc30e375dc43f
pop: d582054913807fd11fd50bfe6a539d91c7e1a55a
- RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669
+ RCT-Folly: fb64616e25cfac1c3d10bfd784d68926325ae67f
RCTDeprecation: f17e2ebc07876ca9ab8eb6e4b0a4e4647497ae3a
RCTRequired: e2c574c1b45231f7efb0834936bd609d75072b63
RCTTypeSafety: c693294e3993056955c3010eb1ebc574f1fcded6
@@ -3946,7 +3946,7 @@ SPEC CHECKSUMS:
react-native-share-extension: fdc6aaab51591a2d445df239c446aaa3a99658ec
react-native-sodium: 066f76e46c9be13e9260521e3fa994937c4cdab4
react-native-theme-switch-animation: 449d6db7a760f55740505e7403ae8061debc9a7e
- react-native-upload: 6285965d20879bcfcf7953f05eb785ba03a60e40
+ react-native-upload: 7b7ad336c3db703b68a8c07cf38e9319ae90d695
react-native-view-shot: 6c008e58f4720de58370848201c5d4a082c6d4ca
react-native-webview: 654f794a7686b47491cf43aa67f7f428bea00eed
React-NativeModulesApple: 46690a0fe94ec28fc6fc686ec797b911d251ded0
@@ -3981,7 +3981,7 @@ SPEC CHECKSUMS:
ReactAppDependencyProvider: a45ef34bb22dc1c9b2ac1f74167d9a28af961176
ReactCodegen: 878add6c7d8ff8cea87697c44d29c03b79b6f2d9
ReactCommon: 804dc80944fa90b86800b43c871742ec005ca424
- RNBackgroundFetch: 0c49d5892a0e2f9c139e24ba498985cf0bf070c6
+ RNBackgroundFetch: 7b9281af0b21100c3c5ef07d1df9ab1adf2dc686
RNBootSplash: 98a34471966945e8dacd1da8f0c2f87cbc2e2df7
RNCCheckbox: 33b44487ca8008394ce658cc32b26eab04f426ef
RNCClipboard: 4b58c780f63676367640f23c8e114e9bd0cf86ac
@@ -3994,7 +3994,7 @@ SPEC CHECKSUMS:
RNIap: 61f183ac917792fae42b0326b1bef33598c1adf6
RNImageCropPicker: 5fd4ceaead64d8c53c787e4e559004f97bc76df7
RNKeychain: ffd0513e676445c637410b47249460cbf56bc9cb
- RNNotifee: c4827fa2cec60ab634d62bafdb5cf57cd2999d54
+ RNNotifee: dea82c9ec44684eeeac9da85deb5eeb8ebe5937f
RNPrivacySnapshot: ccad3a548338c2f526bb7b1789af3fb0618b7d1d
RNReanimated: f1868b36f4b2b52a0ed00062cfda69506f75eaee
RNScreens: ffbb0296608eb3560de641a711bbdb663ed1f6b4
@@ -4005,7 +4005,7 @@ SPEC CHECKSUMS:
RNWorklets: d9c050940f140af5d8b611d937eab1cbfce5e9a5
RNZipArchive: 71befbdc20e7fbd4b64552a0b324ad0e8d0efefb
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
- SexyTooltip: 5c9b4dec52bfb317938cb0488efd9da3717bb6fd
+ SexyTooltip: 605cfd16ae28fd8c3afac9c29236518e156dbbd8
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
SwiftyRSA: 8c6dd1ea7db1b8dc4fb517a202f88bb1354bc2c6
@@ -4013,6 +4013,6 @@ SPEC CHECKSUMS:
toolbar-android: c426ed5bd3dcccfed20fd79533efc0d1ae0ef018
Yoga: 689c8e04277f3ad631e60fe2a08e41d411daf8eb
-PODFILE CHECKSUM: 3021ad3db20df40d4106c9be82d0100d9d447239
+PODFILE CHECKSUM: 3fe13efa8356dcc061862bfa9f453dcd12ede70a
COCOAPODS: 1.16.2
diff --git a/apps/mobile/ios/build-configs/README.md b/apps/mobile/ios/build-configs/README.md
new file mode 100644
index 000000000..fa074bd8b
--- /dev/null
+++ b/apps/mobile/ios/build-configs/README.md
@@ -0,0 +1,41 @@
+# iOS Build Config Switching
+
+This folder controls iOS bundle identifiers and app display name per environment.
+
+## Files
+
+- `ios-build.production.xcconfig`: production identifiers and name
+- `ios-build.staging.xcconfig`: staging identifiers and name
+- `ios-build.active.xcconfig`: active config consumed during build
+- `use-ios-build-config.sh`: helper to switch active config
+
+## Switch Active Config
+
+From `apps/mobile`:
+
+```bash
+bash ios/build-configs/use-ios-build-config.sh production
+bash ios/build-configs/use-ios-build-config.sh staging
+```
+
+## Build With Active Config
+
+Use `xcodebuild` with the active file:
+
+```bash
+xcodebuild \
+ -workspace ios/Notesnook.xcworkspace \
+ -scheme Notesnook \
+ -configuration Release \
+ -xcconfig ios/build-configs/ios-build.active.xcconfig
+```
+
+You can also use a specific config file directly:
+
+```bash
+xcodebuild \
+ -workspace ios/Notesnook.xcworkspace \
+ -scheme Notesnook \
+ -configuration Release \
+ -xcconfig ios/build-configs/ios-build.staging.xcconfig
+```
diff --git a/apps/mobile/ios/build-configs/ios-build.active.xcconfig b/apps/mobile/ios/build-configs/ios-build.active.xcconfig
new file mode 100644
index 000000000..7fa30b5bb
--- /dev/null
+++ b/apps/mobile/ios/build-configs/ios-build.active.xcconfig
@@ -0,0 +1,10 @@
+// Staging iOS build identifiers
+IOS_CURRENT_PROJECT_VERSION = 2178
+IOS_MARKETING_VERSION = 3.3.18
+IOS_MAIN_BUNDLE_ID = org.streetwriters.notesnook
+IOS_WIDGET_BUNDLE_ID = org.streetwriters.notesnook.notewidget
+IOS_SHARE_BUNDLE_ID = org.streetwriters.notesnook.share
+APP_DISPLAY_NAME = Notesnook
+IOS_MAIN_PROFILE = Notesnook Adhoc 2026
+IOS_WIDGET_PROFILE = Notesnook Note Widget Adhoc 2026
+IOS_SHARE_PROFILE = Notesnook Share Adhoc 2026
diff --git a/apps/mobile/ios/build-configs/ios-build.production.xcconfig b/apps/mobile/ios/build-configs/ios-build.production.xcconfig
new file mode 100644
index 000000000..9c57d3bde
--- /dev/null
+++ b/apps/mobile/ios/build-configs/ios-build.production.xcconfig
@@ -0,0 +1,10 @@
+// Production iOS build identifiers
+IOS_CURRENT_PROJECT_VERSION = 2178
+IOS_MARKETING_VERSION = 3.3.18
+IOS_MAIN_BUNDLE_ID = org.streetwriters.notesnook
+IOS_WIDGET_BUNDLE_ID = org.streetwriters.notesnook.notewidget
+IOS_SHARE_BUNDLE_ID = org.streetwriters.notesnook.share
+APP_DISPLAY_NAME = Notesnook
+IOS_MAIN_PROFILE = Notesnook 2026
+IOS_WIDGET_PROFILE = Notesnook Note Widget 2026
+IOS_SHARE_PROFILE = Notesnook Share 2026
diff --git a/apps/mobile/ios/build-configs/ios-build.staging.xcconfig b/apps/mobile/ios/build-configs/ios-build.staging.xcconfig
new file mode 100644
index 000000000..7fa30b5bb
--- /dev/null
+++ b/apps/mobile/ios/build-configs/ios-build.staging.xcconfig
@@ -0,0 +1,10 @@
+// Staging iOS build identifiers
+IOS_CURRENT_PROJECT_VERSION = 2178
+IOS_MARKETING_VERSION = 3.3.18
+IOS_MAIN_BUNDLE_ID = org.streetwriters.notesnook
+IOS_WIDGET_BUNDLE_ID = org.streetwriters.notesnook.notewidget
+IOS_SHARE_BUNDLE_ID = org.streetwriters.notesnook.share
+APP_DISPLAY_NAME = Notesnook
+IOS_MAIN_PROFILE = Notesnook Adhoc 2026
+IOS_WIDGET_PROFILE = Notesnook Note Widget Adhoc 2026
+IOS_SHARE_PROFILE = Notesnook Share Adhoc 2026
diff --git a/apps/mobile/ios/build-configs/use-ios-build-config.sh b/apps/mobile/ios/build-configs/use-ios-build-config.sh
new file mode 100755
index 000000000..feeed7701
--- /dev/null
+++ b/apps/mobile/ios/build-configs/use-ios-build-config.sh
@@ -0,0 +1,99 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+usage() {
+ cat < [--marketing-version ] [--build-number ]
+
+Examples:
+ $0 production
+ $0 staging --marketing-version 3.3.19 --build-number 2179
+EOF
+}
+
+if [[ $# -lt 1 ]]; then
+ usage
+ exit 1
+fi
+
+ENV_NAME="$1"
+shift
+
+MARKETING_VERSION=""
+BUILD_NUMBER=""
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --marketing-version)
+ if [[ $# -lt 2 ]]; then
+ echo "Missing value for --marketing-version"
+ exit 1
+ fi
+ MARKETING_VERSION="$2"
+ shift 2
+ ;;
+ --build-number)
+ if [[ $# -lt 2 ]]; then
+ echo "Missing value for --build-number"
+ exit 1
+ fi
+ BUILD_NUMBER="$2"
+ shift 2
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ *)
+ echo "Unknown argument: $1"
+ usage
+ exit 1
+ ;;
+ esac
+done
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+ACTIVE_FILE="$SCRIPT_DIR/ios-build.active.xcconfig"
+SOURCE_FILE="$SCRIPT_DIR/ios-build.${ENV_NAME}.xcconfig"
+
+if [[ ! -f "$SOURCE_FILE" ]]; then
+ echo "Unknown config '$ENV_NAME'. Expected 'production' or 'staging'."
+ exit 1
+fi
+
+set_or_append_key() {
+ local file="$1"
+ local key="$2"
+ local value="$3"
+ local escaped_value="${value//&/\\&}"
+
+ if grep -Eq "^[[:space:]]*${key}[[:space:]]*=" "$file"; then
+ sed -E -i.bak "s|^[[:space:]]*${key}[[:space:]]*=.*$|${key} = ${escaped_value}|g" "$file"
+ rm -f "$file.bak"
+ else
+ printf "\n%s = %s\n" "$key" "$value" >> "$file"
+ fi
+}
+
+if [[ -n "$MARKETING_VERSION" || -n "$BUILD_NUMBER" ]]; then
+ for xcconfig in "$SCRIPT_DIR"/*.xcconfig; do
+ if [[ -n "$MARKETING_VERSION" ]]; then
+ set_or_append_key "$xcconfig" "IOS_MARKETING_VERSION" "$MARKETING_VERSION"
+ fi
+
+ if [[ -n "$BUILD_NUMBER" ]]; then
+ set_or_append_key "$xcconfig" "IOS_CURRENT_PROJECT_VERSION" "$BUILD_NUMBER"
+ fi
+ done
+fi
+
+cp "$SOURCE_FILE" "$ACTIVE_FILE"
+echo "Active iOS build config set to: $ENV_NAME"
+
+if [[ -n "$MARKETING_VERSION" ]]; then
+ echo "Updated marketing version in all xcconfigs: $MARKETING_VERSION"
+fi
+
+if [[ -n "$BUILD_NUMBER" ]]; then
+ echo "Updated build number in all xcconfigs: $BUILD_NUMBER"
+fi