Skip to content
Draft
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
44 changes: 44 additions & 0 deletions docs/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<version>` and
`<build-number>` with the values from your normal development configuration:

```sh
STACK_IOS_SIMULATOR=1 ./scripts/build_app.sh -a stack_wallet -p ios -v <version> -b <build-number>
flutter pub get
flutter devices
flutter run -d <simulator-device-id>
```

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:
```
Expand Down
6 changes: 6 additions & 0 deletions ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 6 additions & 0 deletions scripts/app_config/configure_stack_duo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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" \
Expand Down
6 changes: 6 additions & 0 deletions scripts/app_config/configure_stack_wallet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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" \
Expand Down
17 changes: 17 additions & 0 deletions scripts/app_config/templates/pubspec.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
107 changes: 107 additions & 0 deletions test/tool/ios_simulator_config_test.dart
Original file line number Diff line number Diff line change
@@ -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<String> args, {Map<String, String>? 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<File>()) {
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<String, String>.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,
);
});
}
}
}
Loading