Skip to content

Commit e0c8591

Browse files
authored
Revert FFI usage on iOS/macOS (#3379)
* Update * Update * Update * Update * Update * Update * Update * Re-add native ios test * Remove unnecessary file * Update * Update * Fix tests * Fix tests * Update * Update * Update CHANGELOG * Update test * Update test * Update test * Update test * Update * Update * Update * Update * Update * Update * Update * Update * Update * Fix compilation * Fix lint * Fix proxy update * Remove todo comment * Update test yml
1 parent a5b28db commit e0c8591

34 files changed

+73720
-7966
lines changed

.github/workflows/flutter_test.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,14 @@ jobs:
6767
avd-name: avd-x86_64-31
6868
emulator-options: -no-snapshot-save -no-window -accel on -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
6969
disable-animations: true
70-
script: flutter test integration_test/all.dart --dart-define SENTRY_AUTH_TOKEN_E2E=$SENTRY_AUTH_TOKEN_E2E --verbose && flutter drive --driver=integration_test/test_driver/driver.dart --target=integration_test/sentry_widgets_flutter_binding_test.dart --profile -d emulator-5554
70+
script: |
71+
flutter test integration_test/all.dart --dart-define SENTRY_AUTH_TOKEN_E2E=$SENTRY_AUTH_TOKEN_E2E --verbose
72+
flutter clean
73+
flutter drive --driver=integration_test/test_driver/driver.dart --target=integration_test/sentry_widgets_flutter_binding_test.dart --profile -d emulator-5554
7174
7275
- name: Build APK
7376
working-directory: packages/flutter/example/android
74-
run: flutter build apk --debug --target-platform=android-x64
77+
run: flutter clean && flutter build apk --debug --target-platform=android-x64
7578

7679
cocoa:
7780
name: '${{ matrix.target }} | ${{ matrix.sdk }}'
@@ -129,6 +132,18 @@ jobs:
129132
run: |
130133
flutter drive --driver=integration_test/test_driver/driver.dart --target=integration_test/sentry_widgets_flutter_binding_test.dart --profile -d "${{ steps.device.outputs.name }}"
131134
135+
- name: run native test
136+
# We only have the native unit test package in the iOS xcodeproj at the moment.
137+
# Should be OK because it will likely be removed after switching to FFI (see https://github.com/getsentry/sentry-dart/issues/1444).
138+
if: ${{ matrix.target == 'ios' }}
139+
working-directory: packages/flutter/example/${{ matrix.target }}
140+
# For some reason running native unit tests directly after Flutter integration tests fails
141+
# running flutter build ios before works: https://stackoverflow.com/a/77487525/22813624
142+
run: |
143+
flutter build ios --no-codesign
144+
xcodebuild test -workspace Runner.xcworkspace -scheme Runner -configuration Debug -destination "platform=$DEVICE_PLATFORM" -allowProvisioningUpdates CODE_SIGNING_ALLOWED=NO
145+
env:
146+
DEVICE_PLATFORM: ${{ steps.device.outputs.platform }}
132147
# TODO(buenaflor): fix the web integration test. The tests pass but the driver keeps hanging so the workflow cancels after 30minutes
133148
# web:
134149
# runs-on: ubuntu-latest

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Fixes
6+
7+
- Revert FFI usage on iOS/macOS due to symbol stripping issues ([#3379](https://github.com/getsentry/sentry-dart/pull/3379))
8+
39
## 9.9.0-beta.3
410

511
### Features

packages/flutter/example/integration_test/integration_test.dart

Lines changed: 80 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ import 'package:package_info_plus/package_info_plus.dart';
1212
import 'package:sentry_flutter/sentry_flutter.dart';
1313
import 'package:sentry_flutter_example/main.dart';
1414
import 'package:sentry_flutter/src/native/java/sentry_native_java.dart';
15-
import 'package:sentry_flutter/src/native/cocoa/sentry_native_cocoa.dart';
1615
import 'package:sentry_flutter/src/native/java/binding.dart' as jni;
17-
import 'package:sentry_flutter/src/native/cocoa/binding.dart' as cocoa;
18-
import 'package:objective_c/objective_c.dart';
1916

2017
import 'utils.dart';
2118

@@ -169,13 +166,8 @@ void main() {
169166
await transaction.finish();
170167
});
171168

172-
testWidgets('init maps Dart options into native SDK options', (tester) async {
173-
if (Platform.isIOS || Platform.isMacOS) {
174-
// Since this is a static var previous test might have overridden this so
175-
// we should set this back to the default (false).
176-
cocoa.PrivateSentrySDKOnly.setAppStartMeasurementHybridSDKMode(false);
177-
}
178-
169+
testWidgets('init maps Dart options into native SDK options on Android',
170+
(tester) async {
179171
await restoreFlutterOnErrorAfter(() async {
180172
await setupSentryWithCustomInit(() async {
181173
await tester.pumpWidget(
@@ -219,140 +211,86 @@ void main() {
219211
options.replay.quality = SentryReplayQuality.high;
220212
options.replay.sessionSampleRate = 0.4;
221213
options.replay.onErrorSampleRate = 0.8;
222-
223-
// Cocoa-only
224-
if (Platform.isIOS || Platform.isMacOS) {
225-
options.recordHttpBreadcrumbs = false;
226-
options.captureFailedRequests = false;
227-
options.enableAppHangTracking = false;
228-
options.appHangTimeoutInterval = const Duration(seconds: 1);
229-
}
230-
// Android-only
231-
if (Platform.isAndroid) {
232-
options.enableNdkScopeSync = true;
233-
options.attachThreads = true;
234-
options.anrEnabled = false;
235-
options.anrTimeoutInterval = const Duration(seconds: 2);
236-
options.connectionTimeout = const Duration(milliseconds: 1234);
237-
options.readTimeout = const Duration(milliseconds: 2345);
238-
}
214+
options.enableNdkScopeSync = true;
215+
options.attachThreads = true;
216+
options.anrEnabled = false;
217+
options.anrTimeoutInterval = const Duration(seconds: 2);
218+
options.connectionTimeout = const Duration(milliseconds: 1234);
219+
options.readTimeout = const Duration(milliseconds: 2345);
239220
});
240221
});
241222

242-
if (Platform.isIOS || Platform.isMacOS) {
243-
final cocoaOptions = cocoa.PrivateSentrySDKOnly.getOptions();
244-
expect(cocoaOptions, isNotNull);
245-
if (Platform.isIOS) {
246-
final nativeReplayOptions =
247-
cocoa.SentryFlutterPlugin.getReplayOptions();
248-
expect(nativeReplayOptions, isNotNull);
249-
expect(nativeReplayOptions!.quality,
250-
cocoa.SentryReplayQuality.SentryReplayQualityHigh);
251-
// Can't use direct comparison because of floating point precision
252-
expect(nativeReplayOptions.sessionSampleRate, closeTo(0.4, 0.001));
253-
expect(nativeReplayOptions.onErrorSampleRate, closeTo(0.8, 0.001));
254-
}
255-
expect(cocoaOptions.dsn?.toDartString(), fakeDsn);
256-
expect(cocoaOptions.debug, isTrue);
257-
expect(cocoaOptions.diagnosticLevel.value, SentryLevel.error.ordinal);
258-
expect(cocoaOptions.environment.toDartString(), 'init-test-env');
259-
expect(cocoaOptions.releaseName?.toDartString(), '1.2.3+9');
260-
expect(cocoaOptions.dist?.toDartString(), '42');
261-
expect(cocoaOptions.sendDefaultPii, isTrue);
262-
expect(cocoaOptions.attachStacktrace, isFalse);
263-
expect(cocoaOptions.maxBreadcrumbs, 7);
264-
expect(cocoaOptions.maxCacheItems, 77);
265-
expect(cocoaOptions.maxAttachmentSize, 512);
266-
expect(cocoaOptions.enableAutoSessionTracking, isFalse);
267-
expect(cocoaOptions.sessionTrackingIntervalMillis, 5000);
268-
expect(cocoaOptions.enableAutoBreadcrumbTracking, isFalse);
269-
expect(cocoaOptions.enableNetworkBreadcrumbs, isFalse);
270-
expect(cocoaOptions.enableCaptureFailedRequests, isFalse);
271-
expect(cocoaOptions.enableAppHangTracking, isFalse);
272-
expect(cocoaOptions.appHangTimeoutInterval, 1);
273-
expect(cocoaOptions.enableSpotlight, isTrue);
274-
expect(cocoaOptions.spotlightUrl.toDartString(),
275-
Sentry.currentHub.options.spotlight.url);
276-
expect(cocoaOptions.sendClientReports, isFalse);
277-
expect(
278-
cocoa.PrivateSentrySDKOnly.getSdkName().toDartString(), cocoaSdkName);
279-
expect(cocoa.PrivateSentrySDKOnly.getAppStartMeasurementHybridSDKMode(),
280-
isFalse);
281-
// currently cannot assert the sdk package and integration since it's attached only
282-
// to the event and we don't have a convenient way to access beforeSend
283-
} else if (Platform.isAndroid) {
284-
final ref = jni.ScopesAdapter.getInstance()?.getOptions().reference;
285-
expect(ref, isNotNull);
286-
final androidOptions = jni.SentryAndroidOptions.fromReference(ref!);
287-
288-
expect(androidOptions, isNotNull);
289-
expect(androidOptions.getDsn()?.toDartString(), fakeDsn);
290-
expect(androidOptions.isDebug(), isTrue);
291-
final diagnostic = androidOptions.getDiagnosticLevel();
292-
expect(
293-
diagnostic,
294-
jni.SentryLevel.ERROR,
295-
);
296-
expect(androidOptions.getEnvironment()?.toDartString(), 'init-test-env');
297-
expect(androidOptions.getRelease()?.toDartString(), '1.2.3+9');
298-
expect(androidOptions.getDist()?.toDartString(), '42');
299-
expect(androidOptions.isSendDefaultPii(), isTrue);
300-
expect(androidOptions.isAttachStacktrace(), isFalse);
301-
expect(androidOptions.isAttachThreads(), isTrue);
302-
expect(androidOptions.getMaxBreadcrumbs(), 7);
303-
expect(androidOptions.getMaxCacheItems(), 77);
304-
expect(androidOptions.getMaxAttachmentSize(), 512);
305-
expect(androidOptions.isEnableScopeSync(), isTrue);
306-
expect(androidOptions.isAnrEnabled(), isFalse);
307-
expect(androidOptions.getAnrTimeoutIntervalMillis(), 2000);
308-
expect(androidOptions.isEnableActivityLifecycleBreadcrumbs(), isFalse);
309-
expect(androidOptions.isEnableAppLifecycleBreadcrumbs(), isFalse);
310-
expect(androidOptions.isEnableSystemEventBreadcrumbs(), isFalse);
311-
expect(androidOptions.isEnableAppComponentBreadcrumbs(), isFalse);
312-
expect(androidOptions.isEnableUserInteractionBreadcrumbs(), isFalse);
313-
expect(androidOptions.getConnectionTimeoutMillis(), 1234);
314-
expect(androidOptions.getReadTimeoutMillis(), 2345);
315-
expect(androidOptions.isEnableSpotlight(), isTrue);
316-
expect(androidOptions.isSendClientReports(), isFalse);
317-
expect(
318-
androidOptions.getSpotlightConnectionUrl()?.toDartString(),
319-
Sentry.currentHub.options.spotlight.url,
320-
);
321-
expect(androidOptions.getSentryClientName()?.toDartString(),
322-
'$androidSdkName/${jni.BuildConfig.VERSION_NAME?.toDartString()}');
323-
expect(androidOptions.getNativeSdkName()?.toDartString(), nativeSdkName);
324-
expect(androidOptions.getSdkVersion()?.getName().toDartString(),
325-
androidSdkName);
326-
expect(androidOptions.getSdkVersion()?.getVersion().toDartString(),
327-
jni.BuildConfig.VERSION_NAME?.toDartString());
328-
final allPackages = androidOptions
329-
.getSdkVersion()
330-
?.getPackageSet()
331-
.map((pkg) {
332-
if (pkg == null) return null;
333-
return SentryPackage(
334-
pkg.getName().toDartString(), pkg.getVersion().toDartString());
335-
})
336-
.nonNulls
337-
.toList();
338-
for (final package in Sentry.currentHub.options.sdk.packages) {
339-
final findMatchingPackage = allPackages?.firstWhere(
340-
(p) => p.name == package.name && p.version == package.version);
341-
expect(findMatchingPackage, isNotNull);
342-
}
343-
final androidProxy = androidOptions.getProxy();
344-
expect(androidProxy, isNotNull);
345-
expect(androidProxy!.getHost()?.toDartString(), 'proxy.local');
346-
expect(androidProxy.getPort()?.toDartString(), '8084');
347-
expect(androidProxy.getUser()?.toDartString(), 'u');
348-
expect(androidProxy.getPass()?.toDartString(), 'p');
349-
final r = androidOptions.getSessionReplay();
350-
expect(r.getQuality(), jni.SentryReplayOptions$SentryReplayQuality.HIGH);
351-
expect(r.getSessionSampleRate(), isNotNull);
352-
expect(r.getOnErrorSampleRate(), isNotNull);
353-
expect(r.isTrackConfiguration(), isFalse);
223+
final ref = jni.ScopesAdapter.getInstance()?.getOptions().reference;
224+
expect(ref, isNotNull);
225+
final androidOptions = jni.SentryAndroidOptions.fromReference(ref!);
226+
227+
expect(androidOptions, isNotNull);
228+
expect(androidOptions.getDsn()?.toDartString(), fakeDsn);
229+
expect(androidOptions.isDebug(), isTrue);
230+
final diagnostic = androidOptions.getDiagnosticLevel();
231+
expect(
232+
diagnostic,
233+
jni.SentryLevel.ERROR,
234+
);
235+
expect(androidOptions.getEnvironment()?.toDartString(), 'init-test-env');
236+
expect(androidOptions.getRelease()?.toDartString(), '1.2.3+9');
237+
expect(androidOptions.getDist()?.toDartString(), '42');
238+
expect(androidOptions.isSendDefaultPii(), isTrue);
239+
expect(androidOptions.isAttachStacktrace(), isFalse);
240+
expect(androidOptions.isAttachThreads(), isTrue);
241+
expect(androidOptions.getMaxBreadcrumbs(), 7);
242+
expect(androidOptions.getMaxCacheItems(), 77);
243+
expect(androidOptions.getMaxAttachmentSize(), 512);
244+
expect(androidOptions.isEnableScopeSync(), isTrue);
245+
expect(androidOptions.isAnrEnabled(), isFalse);
246+
expect(androidOptions.getAnrTimeoutIntervalMillis(), 2000);
247+
expect(androidOptions.isEnableActivityLifecycleBreadcrumbs(), isFalse);
248+
expect(androidOptions.isEnableAppLifecycleBreadcrumbs(), isFalse);
249+
expect(androidOptions.isEnableSystemEventBreadcrumbs(), isFalse);
250+
expect(androidOptions.isEnableAppComponentBreadcrumbs(), isFalse);
251+
expect(androidOptions.isEnableUserInteractionBreadcrumbs(), isFalse);
252+
expect(androidOptions.getConnectionTimeoutMillis(), 1234);
253+
expect(androidOptions.getReadTimeoutMillis(), 2345);
254+
expect(androidOptions.isEnableSpotlight(), isTrue);
255+
expect(androidOptions.isSendClientReports(), isFalse);
256+
expect(
257+
androidOptions.getSpotlightConnectionUrl()?.toDartString(),
258+
Sentry.currentHub.options.spotlight.url,
259+
);
260+
expect(androidOptions.getSentryClientName()?.toDartString(),
261+
'$androidSdkName/${jni.BuildConfig.VERSION_NAME?.toDartString()}');
262+
expect(androidOptions.getNativeSdkName()?.toDartString(), nativeSdkName);
263+
expect(androidOptions.getSdkVersion()?.getName().toDartString(),
264+
androidSdkName);
265+
expect(androidOptions.getSdkVersion()?.getVersion().toDartString(),
266+
jni.BuildConfig.VERSION_NAME?.toDartString());
267+
final allPackages = androidOptions
268+
.getSdkVersion()
269+
?.getPackageSet()
270+
.map((pkg) {
271+
if (pkg == null) return null;
272+
return SentryPackage(
273+
pkg.getName().toDartString(), pkg.getVersion().toDartString());
274+
})
275+
.nonNulls
276+
.toList();
277+
for (final package in Sentry.currentHub.options.sdk.packages) {
278+
final findMatchingPackage = allPackages?.firstWhere(
279+
(p) => p.name == package.name && p.version == package.version);
280+
expect(findMatchingPackage, isNotNull);
354281
}
355-
});
282+
final androidProxy = androidOptions.getProxy();
283+
expect(androidProxy, isNotNull);
284+
expect(androidProxy!.getHost()?.toDartString(), 'proxy.local');
285+
expect(androidProxy.getPort()?.toDartString(), '8084');
286+
expect(androidProxy.getUser()?.toDartString(), 'u');
287+
expect(androidProxy.getPass()?.toDartString(), 'p');
288+
final r = androidOptions.getSessionReplay();
289+
expect(r.getQuality(), jni.SentryReplayOptions$SentryReplayQuality.HIGH);
290+
expect(r.getSessionSampleRate(), isNotNull);
291+
expect(r.getOnErrorSampleRate(), isNotNull);
292+
expect(r.isTrackConfiguration(), isFalse);
293+
}, skip: !Platform.isAndroid);
356294

357295
testWidgets('loads native contexts through loadContexts', (tester) async {
358296
await restoreFlutterOnErrorAfter(() async {
@@ -422,8 +360,8 @@ void main() {
422360
expect(breadcrumbs, isA<List>());
423361
if (breadcrumbs!.isNotEmpty) {
424362
final firstCrumb = breadcrumbs.first;
425-
expect(firstCrumb, isA<Map<String, dynamic>>());
426-
final Map<String, dynamic> crumbMap = firstCrumb as Map<String, dynamic>;
363+
expect(firstCrumb, isA<Map>());
364+
final crumbMap = firstCrumb as Map;
427365
expect(crumbMap.containsKey('timestamp'), isTrue,
428366
reason: 'Breadcrumb timestamp missing');
429367
expect(crumbMap['timestamp'], isA<String>());

packages/flutter/example/integration_test/profiling_test.dart

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ import 'dart:convert';
22
import 'dart:io';
33

44
import 'package:flutter_test/flutter_test.dart';
5+
import 'package:integration_test/integration_test.dart';
56
import 'package:sentry_flutter/sentry_flutter.dart';
7+
import 'package:sentry_flutter_example/main.dart';
68
import '../../../dart/test/mocks/mock_transport.dart';
79

810
void main() {
11+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
12+
913
final transport = MockTransport();
1014

11-
setUp(() async {
15+
Future<void> setupSentryAndApp(WidgetTester tester) async {
1216
await SentryFlutter.init((options) {
1317
// ignore: invalid_use_of_internal_member
1418
options.automatedTestMode = true;
@@ -17,20 +21,24 @@ void main() {
1721
options.transport = transport;
1822
options.tracesSampleRate = 1.0;
1923
options.profilesSampleRate = 1.0;
24+
}, appRunner: () async {
25+
await tester.pumpWidget(const MyApp());
2026
});
21-
});
27+
}
2228

2329
tearDown(() async {
2430
await Sentry.close();
2531
transport.reset();
2632
});
2733

28-
test('native binding is initialized', () async {
34+
testWidgets('native binding is initialized', (tester) async {
35+
await setupSentryAndApp(tester);
2936
// ignore: invalid_use_of_internal_member
3037
expect(SentryFlutter.native, isNotNull);
3138
});
3239

33-
test('profile is captured', () async {
40+
testWidgets('profile is captured', (tester) async {
41+
await setupSentryAndApp(tester);
3442
final tx = Sentry.startTransaction("name", "op");
3543
await Future.delayed(const Duration(milliseconds: 1000));
3644
await tx.finish();
@@ -63,8 +71,5 @@ void main() {
6371
expect(profileMap["profile"]["samples"], isNotEmpty);
6472
expect(profileMap["profile"]["stacks"], isNotEmpty);
6573
expect(profileMap["profile"]["frames"], isNotEmpty);
66-
},
67-
skip: (Platform.isMacOS || Platform.isIOS)
68-
? false
69-
: "Profiling is not supported on this platform");
74+
}, skip: !(Platform.isMacOS || Platform.isIOS));
7075
}

0 commit comments

Comments
 (0)