diff --git a/docs/building.md b/docs/building.md index ab99a2e8e..dfeb5fc0b 100644 --- a/docs/building.md +++ b/docs/building.md @@ -280,6 +280,50 @@ flutter pub get flutter run ios ``` +#### iOS Simulator (arm64/Apple Silicon) + +Simulator configuration is experimental and requires an Apple Silicon Mac, +Xcode, and an installed iOS simulator runtime. It selects older review-pinned +Monero and Wownero iOS packages that include arm64 simulator slices. Normal +configuration keeps the released device dependencies; other platforms ignore +this option. Stack Duo selects only the Monero override. + +Configure Stack Wallet from the repository root. Replace `` and +`` with the values from your normal development configuration: + +```sh +STACK_IOS_SIMULATOR=1 ./scripts/build_app.sh -a stack_wallet -p ios -v -b +flutter pub get +flutter devices +flutter run -d +``` + +Replace `stack_wallet` with `stack_duo` for Duo. Follow the version/build-number +prompt carefully: changing those values can affect local wallet data. Use a +separate development checkout and disposable test wallets for simulator work. +To return to device builds, rerun configuration without `STACK_IOS_SIMULATOR`, +then run `flutter pub get` again. Do not commit a simulator-only lockfile update. + +The former Frost, Epic Cash, and MWC submodules now use Flutter Native Assets +packages. Their build hooks compile or fetch libraries during the Flutter build; +the removed crypto-plugin +submodule build scripts and Cargokit instructions no longer apply. Install the +native toolchains listed above, including Rustup, CMake, and Go. Every enabled +native dependency must support the selected simulator SDK; selecting the +Monero/Wownero slices alone does not verify a complete simulator build. + +The CocoaPods configuration excludes `i386` and `x86_64` simulator architectures, +so this setup targets arm64 simulators. If Xcode reports that the required iOS +runtime is missing, install it in Xcode's platform settings or with +`xcodebuild -downloadPlatform iOS`. + +The simulator pins have not been refreshed to the current device-library ABI. +The Monero simulator pin lacks `MONERO_Wallet_serializeCacheToJson`, which the +released device library exports. Stack Wallet does not currently call that +symbol, but the mismatch prevents treating this configuration as release-ready. +A macOS simulator build and wallet smoke test are still required; Linux +configuration checks cannot verify Apple SDK linking or runtime behavior. + #### macOS Run the following commands or launch via Android Studio: ``` diff --git a/ios/Podfile b/ios/Podfile index f17bddc91..00dcb91c1 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -37,5 +37,11 @@ end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) + target.build_configurations.each do |config| + # Several vendored crypto libraries ship arm64-only simulator slices; + # exclude x86_64 (and legacy i386) so simulator builds on Apple Silicon + # don't try to build/link missing x86_64 slices. + config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'i386 x86_64' + end end end diff --git a/scripts/app_config/configure_stack_duo.sh b/scripts/app_config/configure_stack_duo.sh index 2949d80cd..ba9b449dc 100755 --- a/scripts/app_config/configure_stack_duo.sh +++ b/scripts/app_config/configure_stack_duo.sh @@ -26,6 +26,12 @@ dart "${APP_PROJECT_ROOT_DIR}/tool/process_pubspec_deps.dart" \ TOR \ FROST +# Review-pinned simulator libraries are separate from normal device dependencies. +if [[ "$1" == "ios" && "${STACK_IOS_SIMULATOR:-0}" == "1" ]]; then + dart "${APP_PROJECT_ROOT_DIR}/tool/process_pubspec_deps.dart" \ + "${PUBSPEC_FILE}" XMR_IOS_SIMULATOR +fi + dart "${APP_PROJECT_ROOT_DIR}/tool/gen_interfaces.dart" \ "${APP_PROJECT_ROOT_DIR}/tool/wl_templates" \ "${APP_PROJECT_ROOT_DIR}/lib/wl_gen/generated" \ diff --git a/scripts/app_config/configure_stack_wallet.sh b/scripts/app_config/configure_stack_wallet.sh index 6f41d27b7..564d4c840 100755 --- a/scripts/app_config/configure_stack_wallet.sh +++ b/scripts/app_config/configure_stack_wallet.sh @@ -33,6 +33,12 @@ dart "${APP_PROJECT_ROOT_DIR}/tool/process_pubspec_deps.dart" \ XEL \ FROST +# Review-pinned simulator libraries are separate from normal device dependencies. +if [[ "$1" == "ios" && "${STACK_IOS_SIMULATOR:-0}" == "1" ]]; then + dart "${APP_PROJECT_ROOT_DIR}/tool/process_pubspec_deps.dart" \ + "${PUBSPEC_FILE}" XMR_IOS_SIMULATOR WOW_IOS_SIMULATOR +fi + dart "${APP_PROJECT_ROOT_DIR}/tool/gen_interfaces.dart" \ "${APP_PROJECT_ROOT_DIR}/tool/wl_templates" \ "${APP_PROJECT_ROOT_DIR}/lib/wl_gen/generated" \ diff --git a/scripts/app_config/templates/pubspec.template.yaml b/scripts/app_config/templates/pubspec.template.yaml index 6c576862e..565463abf 100644 --- a/scripts/app_config/templates/pubspec.template.yaml +++ b/scripts/app_config/templates/pubspec.template.yaml @@ -347,6 +347,23 @@ dependency_overrides: freezed: ^3.1.0 freezed_annotation: ^3.1.0 +# Experimental simulator pins are opt-in; device builds keep released packages. +# %%ENABLE_XMR_IOS_SIMULATOR%% +# cs_monero_flutter_libs_ios: +# git: +# url: https://github.com/cypherstack/cs_monero +# path: cs_monero_flutter_libs_ios +# ref: d89ab9f9bc18fa610c8bd629ad8fbbfc7a0c6d5b +# %%END_ENABLE_XMR_IOS_SIMULATOR%% + +# %%ENABLE_WOW_IOS_SIMULATOR%% +# cs_wownero_flutter_libs_ios: +# git: +# url: https://github.com/cypherstack/cs_wownero +# path: cs_wownero_flutter_libs_ios +# ref: 8cf5b879126dd8f11bde632ef8e7d2f088d95988 +# %%END_ENABLE_WOW_IOS_SIMULATOR%% + # %%ENABLE_ISAR%% # isar_community: # git: diff --git a/test/tool/ios_simulator_config_test.dart b/test/tool/ios_simulator_config_test.dart new file mode 100644 index 000000000..16d6aa13a --- /dev/null +++ b/test/tool/ios_simulator_config_test.dart @@ -0,0 +1,107 @@ +import 'dart:io'; + +import 'package:test/test.dart'; + +void main() { + final project = Directory.current; + late Directory fixture; + + void run(String executable, List args, {Map? env}) { + final result = Process.runSync( + executable, + args, + workingDirectory: fixture.path, + environment: env, + includeParentEnvironment: env == null, + ); + expect(result.exitCode, 0, reason: '${result.stdout}\n${result.stderr}'); + } + + setUpAll(() { + fixture = Directory.systemTemp.createTempSync('stack-simulator-config-'); + Directory('${fixture.path}/tool/wl_templates').createSync(recursive: true); + Directory('${fixture.path}/lib/wl_gen/generated') + .createSync(recursive: true); + for (final name in ['process_pubspec_deps.dart', 'gen_interfaces.dart']) { + File('${project.path}/tool/$name').copySync('${fixture.path}/tool/$name'); + } + for (final template in Directory( + '${project.path}/tool/wl_templates', + ).listSync().whereType()) { + template.copySync( + '${fixture.path}/tool/wl_templates/${template.uri.pathSegments.last}', + ); + } + // The real configure scripts record git's revision in generated app config. + // Give the isolated fixture its own revision; never modify the checkout. + run('git', ['-C', fixture.path, 'init', '--quiet']); + run('git', [ + '-C', + fixture.path, + '-c', + 'user.name=Config Test', + '-c', + 'user.email=config-test@example.invalid', + '-c', + 'commit.gpgsign=false', + '-c', + 'core.hooksPath=/dev/null', + 'commit', + '--allow-empty', + '--quiet', + '-m', + 'Configuration fixture', + ]); + }); + + tearDownAll(() => fixture.deleteSync(recursive: true)); + + for (final app in ['stack_wallet', 'stack_duo']) { + for (final scenario in <({String platform, String? flag})>[ + (platform: 'ios', flag: null), + (platform: 'ios', flag: '0'), + (platform: 'ios', flag: '1'), + (platform: 'android', flag: '1'), + (platform: 'macos', flag: '1'), + (platform: 'linux', flag: '1'), + ]) { + test('$app ${scenario.platform} ' + 'simulator=${scenario.flag ?? "unset"}', () { + final pubspec = File('${fixture.path}/pubspec.yaml'); + File( + '${project.path}/scripts/app_config/templates/pubspec.template.yaml', + ).copySync(pubspec.path); + final env = Map.from(Platform.environment) + ..remove('STACK_IOS_SIMULATOR') + ..['APP_PROJECT_ROOT_DIR'] = fixture.path; + if (scenario.flag != null) env['STACK_IOS_SIMULATOR'] = scenario.flag!; + run('bash', [ + '${project.path}/scripts/app_config/configure_$app.sh', + scenario.platform, + ], env: env); + + final generated = pubspec.readAsStringSync(); + final simulator = scenario.platform == 'ios' && scenario.flag == '1'; + final overrides = generated.split('dependency_overrides:').last; + bool enabled(String package) => + RegExp('^ $package:', multiLine: true).hasMatch(overrides); + expect(enabled('cs_monero_flutter_libs_ios'), simulator); + expect( + enabled('cs_wownero_flutter_libs_ios'), + simulator && app == 'stack_wallet', + ); + expect( + enabled('flutter_mwebd'), + isFalse, + reason: + 'simulator configuration must not downgrade ' + 'the native-assets MWEB package', + ); + expect( + File('${fixture.path}/lib/app_config.g.dart').existsSync(), + isTrue, + ); + }); + } + } +}