From 466b1e9bd4a0cfc8c1a4767fa570135b8ab13343 Mon Sep 17 00:00:00 2001 From: Yogendra Shelke Date: Thu, 20 Nov 2025 16:41:43 +0530 Subject: [PATCH 1/5] chore: update template --- .gitignore | 1 + capabilities-setup-config.json | 30 +++--------- ios/AppDelegate.swift | 11 +---- ios/Dev/AppDelegate.swift | 11 ++--- ios/MendixAppDelegate.swift | 42 ----------------- ios/mendix_utils.rb | 83 ++++++++++------------------------ 6 files changed, 36 insertions(+), 142 deletions(-) delete mode 100644 ios/MendixAppDelegate.swift diff --git a/.gitignore b/.gitignore index 397437478..eac7eb429 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ local.properties # **/Pods/ ios/MendixAppDelegate.m +ios/MendixAppDelegate.swift # node.js # diff --git a/capabilities-setup-config.json b/capabilities-setup-config.json index 15da292c9..b2852bab0 100644 --- a/capabilities-setup-config.json +++ b/capabilities-setup-config.json @@ -3,10 +3,10 @@ "ios": { "AppDelegate": { "imports": [ - "#import \"React/RCTLinkingManager.h\"" + "import React" ], "boolean_openURLWithOptions": [ - "return [RCTLinkingManager application:application openURL:url options:options];" + "return RCTLinkingManager.application(application, open: url, options: options)" ] } } @@ -36,24 +36,6 @@ "externalDependencies": [ "me.leolin:ShortcutBadger:1.1.22@aar" ] - }, - "ios": { - "AppDelegate": { - "imports": [ - "#import " - ], - "didFinishLaunchingWithOptions": [ - "UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];", - "center.delegate = MendixAppDelegate.delegate;" - ], - "willPresentNotification": [ - "completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);" - ], - "didReceiveNotificationResponse": [ - "[RNCPushNotificationIOS didReceiveNotificationResponse:response];", - "completionHandler();" - ] - } } }, "firebaseAndroid": { @@ -72,10 +54,10 @@ "ios": { "AppDelegate": { "imports": [ - "#import " + "import FirebaseCore" ], "didFinishLaunchingWithOptions": [ - "[FIRApp configure];" + "FirebaseApp.configure()" ] } } @@ -85,10 +67,10 @@ "ios": { "AppDelegate": { "imports": [ - "#import " + "import GoogleMaps" ], "didFinishLaunchingWithOptions": [ - "[GMSServices provideAPIKey:[[NSBundle mainBundle] objectForInfoDictionaryKey:@\"GoogleMapsApiKey\"] ?: @\"\"];" + "GMSServices.provideAPIKey(Bundle.main.object(forInfoDictionaryKey: \"GoogleMapsApiKey\") as? String ?? \"\")" ] }, "pods": { diff --git a/ios/AppDelegate.swift b/ios/AppDelegate.swift index 9e8abf9bf..799ae945a 100644 --- a/ios/AppDelegate.swift +++ b/ios/AppDelegate.swift @@ -1,18 +1,15 @@ import MendixNative @UIApplicationMain -class AppDelegate: ReactAppProvider, UNUserNotificationCenterDelegate { +class AppDelegate: ReactAppProvider { var shouldOpenInLastApp = false var hasHandledLaunchAppWithOptions = false override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { - setupApp(application: application, launchOptions: launchOptions) - MendixAppDelegate.delegate = self - UNUserNotificationCenter.current().delegate = self MendixAppDelegate.application(application, didFinishLaunchingWithOptions: launchOptions) - + setupApp(application: application, launchOptions: launchOptions) changeRoot(to: UIViewController()) guard let url = Bundle.main.object(forInfoDictionaryKey: "Runtime url") as? String, !url.isEmpty else { @@ -58,8 +55,4 @@ class AppDelegate: ReactAppProvider, UNUserNotificationCenterDelegate { func getWarningFilterValue() -> WarningsFilter { return .none } - - func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { - MendixAppDelegate.userNotificationCenter(center, willPresentNotification: notification, withCompletionHandler: completionHandler) - } } diff --git a/ios/Dev/AppDelegate.swift b/ios/Dev/AppDelegate.swift index c0ba97f7c..c6e398093 100644 --- a/ios/Dev/AppDelegate.swift +++ b/ios/Dev/AppDelegate.swift @@ -2,16 +2,15 @@ import Foundation import MendixNative @UIApplicationMain -class AppDelegate: ReactAppProvider, UNUserNotificationCenterDelegate { +class AppDelegate: ReactAppProvider { var shouldOpenInLastApp = false var hasHandledLaunchAppWithOptions = false override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { - setupApp(application: application, launchOptions: launchOptions) - MendixAppDelegate.delegate = self - UNUserNotificationCenter.current().delegate = self + MendixAppDelegate.application(application, didFinishLaunchingWithOptions: launchOptions) + setupApp(application: application, launchOptions: launchOptions) IQKeyboardManager.shared().isEnabled = false @@ -22,10 +21,6 @@ class AppDelegate: ReactAppProvider, UNUserNotificationCenterDelegate { return true } - func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { - MendixAppDelegate.userNotificationCenter(center, willPresentNotification: notification, withCompletionHandler: completionHandler) - } - func getWarningFilterValue() -> WarningsFilter { #if DEBUG return .all diff --git a/ios/MendixAppDelegate.swift b/ios/MendixAppDelegate.swift deleted file mode 100644 index e98ce7743..000000000 --- a/ios/MendixAppDelegate.swift +++ /dev/null @@ -1,42 +0,0 @@ -import Foundation -import UIKit -import UserNotifications -import React -import MendixNative - -class MendixAppDelegate: NSObject { - - static var delegate: (UIResponder & UIApplicationDelegate & UNUserNotificationCenterDelegate)? - - static func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { - - } - - static func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { - - } - - static func application(_ application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) { - - } - - static func application(_ application: UIApplication, openURL url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { - return true - } - - static func application(_ application: UIApplication, openURL url: URL, sourceApplication: String?, annotation: Any) { - - } - - static func userNotificationCenter(_ center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { - - } - - static func userNotificationCenter(_ center: UNUserNotificationCenter, didReceiveNotificationResponse response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { - - } - - static func getJSBundleFile() -> URL? { - return BundleHelper.getJSBundleFile() - } -} diff --git a/ios/mendix_utils.rb b/ios/mendix_utils.rb index f9764bafd..f41c2c59c 100644 --- a/ios/mendix_utils.rb +++ b/ios/mendix_utils.rb @@ -37,12 +37,7 @@ def generate_mendix_delegate imports = [] hooks = { didFinishLaunchingWithOptions: [], - didReceiveLocalNotification: [], - didReceiveRemoteNotification: [], - didRegisterUserNotificationSettings: [], openURL: [], - willPresentNotification: [], - didReceiveNotificationResponse: [], getJSBundleFile: [], } @@ -77,72 +72,42 @@ def generate_mendix_delegate end end - File.open("MendixAppDelegate.m", "w") do |file| + File.open("MendixAppDelegate.swift", "w") do |file| mendix_app_delegate = mendix_app_delegate_template.sub("{{ imports }}", stringify(imports)) hooks.each { |name, hook| mendix_app_delegate.sub!("{{ #{name.to_s} }}", stringify(hook)) } - returnHooks.each { |name, hook| mendix_app_delegate.sub!("{{ #{name.to_s} }}", stringify(hook).length > 0 ? stringify(hook) : " return YES;") } + returnHooks.each { |name, hook| mendix_app_delegate.sub!("{{ #{name.to_s} }}", stringify(hook).length > 0 ? stringify(hook) : " return true") } file << mendix_app_delegate end end def mendix_app_delegate_template %(// DO NOT EDIT BY HAND. THIS FILE IS AUTO-GENERATED -#import -#import -#import "MendixAppDelegate.h" +import Foundation +import MendixNative {{ imports }} -@implementation MendixAppDelegate - -static UIResponder *_Nullable delegate; - -+ (void) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { -{{ didFinishLaunchingWithOptions }} -} - -+ (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { -{{ didReceiveLocalNotification }} -} - -+ (void) application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo -fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{ -{{ didReceiveRemoteNotification }} -} - -+ (void) application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { -{{ didRegisterUserNotificationSettings }} -} - -+ (BOOL) application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { -{{ boolean_openURLWithOptions }} -} - -+ (void) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { -{{ openURL }} -} - -+ (void) userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { -{{ willPresentNotification }} -} - -+ (void) userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { -{{ didReceiveNotificationResponse }} -} - -+ (UIResponder *_Nullable) delegate { - return delegate; -} - -+ (void) setDelegate:(UIResponder *_Nonnull)value { - delegate = value; -} +/// Auto-generated implementation of MendixAppDelegate +/// Generated based on enabled capabilities in capabilities.ios.json +class MendixAppDelegate: NSObject { + + static func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { + {{ didFinishLaunchingWithOptions }} + } -+ (NSURL *) getJSBundleFile { -{{ getJSBundleFile }} - return [ReactNative.instance getJSBundleFile]; + static func application(_ application: UIApplication, openURL url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { + {{ boolean_openURLWithOptions }} + } + + static func application(_ application: UIApplication, openURL url: URL, sourceApplication: String?, annotation: Any) { + {{ openURL }} + } + + static func getJSBundleFile() -> URL? { + {{ getJSBundleFile }} + return BundleHelper.getJSBundleFile() + } } - -@end\n) +) end def stringify(array) From 73c468583058abe176516bc91aa68ec6c24052f3 Mon Sep 17 00:00:00 2001 From: Yogendra Shelke Date: Thu, 20 Nov 2025 17:36:42 +0530 Subject: [PATCH 2/5] chore: add script to remove stale files --- package.json | 1 + scripts/delete-stale-files.js | 148 ++++++++++++++++++++++++++++++++++ stale_files | 14 ++++ 3 files changed, 163 insertions(+) create mode 100644 scripts/delete-stale-files.js create mode 100644 stale_files diff --git a/package.json b/package.json index 58bd42ef6..9b06ece58 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "15.4.4", "private": true, "scripts": { + "preinstall": "node scripts/delete-stale-files.js", "postinstall": "node patches/apply-patches.js && jetify", "configure": "native-mobile-toolkit configure --config-path='./config.json' --verbose" }, diff --git a/scripts/delete-stale-files.js b/scripts/delete-stale-files.js new file mode 100644 index 000000000..9aa82a1a3 --- /dev/null +++ b/scripts/delete-stale-files.js @@ -0,0 +1,148 @@ +#!/usr/bin/env node + +/** + * Cross-platform script to delete stale files listed in .stale_files + * Works on Windows, macOS, and Linux + * + * This script is designed to run during npm preinstall lifecycle + * to clean up obsolete files before dependencies are installed. + */ + +const fs = require('fs'); +const path = require('path'); + +// Configuration +const STALE_FILES_NAME = 'stale_files'; + +// Determine the root directory (project root) +const rootDir = path.resolve(__dirname, '..'); +const staleFilesPath = path.join(rootDir, STALE_FILES_NAME); + +/** + * Validates if a path is within the project root directory + * @param {string} targetPath - Absolute path to validate + * @param {string} rootPath - Root directory path + * @returns {boolean} - True if path is within root, false otherwise + */ +function isPathWithinRoot(targetPath, rootPath) { + const relative = path.relative(rootPath, targetPath); + return !relative.startsWith('..') && !path.isAbsolute(relative); +} + +/** + * Safely delete a file or directory + * @param {string} filePath - Absolute path to the file/directory + * @param {string} rootPath - Root directory path for validation + * @returns {boolean} - True if deleted successfully, false otherwise + */ +function deleteFileOrDirectory(filePath, rootPath) { + try { + // Validate path is within project root (security check) + if (!isPathWithinRoot(filePath, rootPath)) { + console.log(`⊘ Skipped (outside project): ${filePath}`); + return false; + } + + // Check if file/directory exists + if (!fs.existsSync(filePath)) { + console.log(`⊘ Not found (skipped): ${filePath}`); + return false; + } + + const stats = fs.statSync(filePath); + + if (stats.isDirectory()) { + // Remove directory recursively + fs.rmSync(filePath, { recursive: true, force: true }); + console.log(`✓ Deleted directory: ${filePath}`); + } else { + // Remove file + fs.unlinkSync(filePath); + console.log(`✓ Deleted file: ${filePath}`); + } + return true; + } catch (error) { + // Catch any errors but continue without throwing + console.log(`⊘ Could not delete (skipped): ${filePath} - ${error.message}`); + return false; + } +} + +/** + * Parse and validate file paths from .stale_files content + * @param {string} content - Raw content from .stale_files + * @returns {string[]} - Array of valid file paths + */ +function parseStaleFiles(content) { + return content + .split(/\r?\n/) // Handle both Unix and Windows line endings + .map(line => line.trim()) + .filter(line => line.length > 0); // Filter out empty lines +} + +/** + * Main function to process and delete stale files + * @returns {void} + */ +function deleteStaleFiles() { + console.log('🧹 Starting stale files cleanup...\n'); + + // Verify we're running in a valid project root + if (!fs.existsSync(rootDir)) { + console.warn(`⚠ Warning: Project root directory not found: ${rootDir}`); + console.log('Skipping stale files cleanup.\n'); + return; + } + + // Check if .stale_files exists + if (!fs.existsSync(staleFilesPath)) { + console.log(`⚠ No ${STALE_FILES_NAME} found. Nothing to clean up.`); + return; + } + + let content; + try { + // Read the .stale_files content + content = fs.readFileSync(staleFilesPath, 'utf8'); + } catch (error) { + console.warn(`⚠ Warning: Could not read ${STALE_FILES_NAME}:`, error.message); + console.log('Skipping stale files cleanup.\n'); + return; + } + + const files = parseStaleFiles(content); + + if (files.length === 0) { + console.log(`⚠ No files listed in ${STALE_FILES_NAME}. Nothing to clean up.`); + return; + } + + console.log(`Found ${files.length} file(s)/directory(ies) to process:\n`); + + let deletedCount = 0; + let skippedCount = 0; + + // Process each file + files.forEach(file => { + const absolutePath = path.join(rootDir, file); + const deleted = deleteFileOrDirectory(absolutePath, rootDir); + + if (deleted) { + deletedCount++; + } else { + skippedCount++; + } + }); + + // Summary + console.log('\n=================================================='); + console.log('📊 Cleanup Summary:'); + console.log(` ✓ Deleted: ${deletedCount}`); + console.log(` ⊘ Skipped: ${skippedCount}`); + console.log('==================================================\n'); +} + +// Main execution +if (require.main === module) { + deleteStaleFiles(); +} diff --git a/stale_files b/stale_files new file mode 100644 index 000000000..f74045eb6 --- /dev/null +++ b/stale_files @@ -0,0 +1,14 @@ +patches/@op-engineering+op-sqlite+12.0.2.patch +mendix-native-10.2.2.tgz +ios/AppDelegate.h +ios/AppDelegate.m +ios/MendixAppDelegate.h +ios/MendixAppDelegate.m +ios/main.m +ios/RNSplashScreen+StoryBoardSplash.h +ios/SplashScreenPresenter.h +ios/SplashScreenPresenter.m +ios/StoryBoardSplash.m +ios/SwiftInterop.swift +ios/Dev/AppDelegate.h +ios/Dev/AppDelegate.m \ No newline at end of file From 1e5c67f565dd6c3def2750beb9f7258b386f62d8 Mon Sep 17 00:00:00 2001 From: Yogendra Shelke Date: Thu, 20 Nov 2025 17:46:18 +0530 Subject: [PATCH 3/5] chore: remove stale file --- ios/Dev/AppDelegate.h | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 ios/Dev/AppDelegate.h diff --git a/ios/Dev/AppDelegate.h b/ios/Dev/AppDelegate.h deleted file mode 100644 index 4abc56d3d..000000000 --- a/ios/Dev/AppDelegate.h +++ /dev/null @@ -1,10 +0,0 @@ -#import -#import -#import - -@interface AppDelegate : UIResponder - -@property (nonatomic, strong) UIWindow *window; -@property BOOL shouldOpenInLastApp; -@property BOOL hasHandledLaunchAppWithOptions; -@end From f898c1c805a2fbca9f0ad9d166912abe5f1a5bae Mon Sep 17 00:00:00 2001 From: Yogendra Shelke Date: Thu, 20 Nov 2025 17:50:34 +0530 Subject: [PATCH 4/5] chore: update mendix version mapping and changelog --- CHANGELOG.md | 2 ++ mendix_version.json | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75ed7f94f..9c0f325fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +- We have updated native template to support react native new architecture. + - We have migrated from `react-native-splash-screen@3.2.0` to `react-native-bootsplash@^7.7.0` for better splash screen support and autolinking compatibility. - We added a new property to gradle.properties for scanning QR codes. diff --git a/mendix_version.json b/mendix_version.json index 55b3df262..0f006138f 100644 --- a/mendix_version.json +++ b/mendix_version.json @@ -1,6 +1,10 @@ { - ">=11.0.0": { + ">=11.5.0": { "max": "*", + "min": "16.0.0" + }, + ">=11.0.0": { + "max": "15.*.*", "min": "15.0.0" }, ">=10.24.0": { From acd7b149a4897b82528fe5d4ed2823df6348f921 Mon Sep 17 00:00:00 2001 From: Yogendra Shelke Date: Thu, 20 Nov 2025 18:37:11 +0530 Subject: [PATCH 5/5] chore: remove excluded architecture --- ios/nativeTemplate.xcodeproj/project.pbxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ios/nativeTemplate.xcodeproj/project.pbxproj b/ios/nativeTemplate.xcodeproj/project.pbxproj index 9b0ca4597..1f2f8c15e 100644 --- a/ios/nativeTemplate.xcodeproj/project.pbxproj +++ b/ios/nativeTemplate.xcodeproj/project.pbxproj @@ -692,6 +692,7 @@ DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = BC32QNM6AD; ENABLE_BITCODE = "$(inherited)"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "\"${PODS_ROOT}/FirebaseAnalytics/Frameworks\"", @@ -772,6 +773,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = BC32QNM6AD; ENABLE_BITCODE = "$(inherited)"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "\"${PODS_ROOT}/FirebaseAnalytics/Frameworks\"", @@ -860,6 +862,7 @@ DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = BC32QNM6AD; ENABLE_BITCODE = "$(inherited)"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "${SRCROOT}/../node_modules/@mendix/native/ios", @@ -916,6 +919,7 @@ DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = BC32QNM6AD; ENABLE_BITCODE = "$(inherited)"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "${SRCROOT}/../node_modules/@mendix/native/ios", @@ -1029,6 +1033,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = BC32QNM6AD; ENABLE_BITCODE = "$(inherited)"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "\"${PODS_ROOT}/FirebaseAnalytics/Frameworks\"", @@ -1118,6 +1123,7 @@ DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = BC32QNM6AD; ENABLE_BITCODE = "$(inherited)"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "${SRCROOT}/../node_modules/@mendix/native/ios",