Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: irmagobridge's Stop method not called on iOS #256

Merged
merged 3 commits into from
Nov 22, 2023
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
### Fixed
- irmagobridge's Stop method is not called on iOS when the app is terminated

## [7.5.3] - 2023-11-16
### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ public class MainActivity extends FlutterActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
// We do both these steps before calling parent, to ensure that this always happens before starting the flutter
// engine and attaching its plugins
// We do both these steps before calling parent, to ensure that this always
// happens before starting the flutter engine and attaching its plugins

// Initialize the Go binding here by calling a seemingly noop function
Irmagobridge.prestart();

// Capture initial url only during onCreate, for use during first engine instantiation
// Capture initial url only during onCreate, for use during first engine
// instantiation
this.initialURL = getIntent().getData();

// Hand of to parent
Expand All @@ -48,7 +49,9 @@ public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
flutterEngine.getPlugins().add(new IIABPlugin());

// Start up the irmamobile bridge
MethodChannel channel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "irma.app/irma_mobile_bridge");
MethodChannel channel = new MethodChannel(
flutterEngine.getDartExecutor().getBinaryMessenger(),
"irma.app/irma_mobile_bridge");
bridge = new IrmaMobileBridge(this, this, channel, initialURL);
channel.setMethodCallHandler(bridge);
initialURL = null; // Ensure we only use the initialURL once
Expand All @@ -58,12 +61,16 @@ public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (bridge != null) bridge.onNewIntent(intent);
if (bridge != null) {
bridge.onNewIntent(intent);
}
}

@Override
protected void onDestroy() {
Irmagobridge.stop();
if (bridge != null) {
bridge.stop();
}
super.onDestroy();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,8 @@ public void debugLog(String message) {
if (debug)
System.out.printf("[IrmaMobileBridgePlugin] %s\n", message);
}

public void stop() {
Irmagobridge.stop();
}
}
1 change: 1 addition & 0 deletions ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,7 @@
PRODUCT_BUNDLE_IDENTIFIER = foundation.privacybydesign.irmamob.alpha;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "Local development profile";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
Expand Down
20 changes: 12 additions & 8 deletions ios/Runner/IrmaMobileBridgePlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class IrmaMobileBridgePlugin: NSObject, IrmagobridgeIrmaMobileBridgeProtocol, Fl
private var nativeError: String?
private var appReady: Bool


/// Private constructor. This constructor is called indirectly via register (see below).
/// - Parameters:
/// - channel: Channel to send messages to the Flutter side
Expand All @@ -21,7 +20,6 @@ class IrmaMobileBridgePlugin: NSObject, IrmagobridgeIrmaMobileBridgeProtocol, Fl
super.init()
}


/// Calls the Start method of irmagobridge.
private func start() {
let bundlePath = Bundle.main.bundlePath
Expand Down Expand Up @@ -54,7 +52,12 @@ class IrmaMobileBridgePlugin: NSObject, IrmagobridgeIrmaMobileBridgeProtocol, Fl

IrmagobridgeStart(self, libraryPath, bundlePath, TEE(), aesKey)
}


/// Calls the Stop method of irmagobridge.
private func stop() {
debugLog("Stopping irmago")
IrmagobridgeStop()
}

/// Implements the register method of the FlutterPlugin interface. This method is called by Flutter to bootstrap the plugin.
/// - Parameter registrar: Registration context of the Flutter plugin
Expand All @@ -68,8 +71,7 @@ class IrmaMobileBridgePlugin: NSObject, IrmagobridgeIrmaMobileBridgeProtocol, Fl
registrar.addMethodCallDelegate(instance, channel: channel)
registrar.addApplicationDelegate(instance)
}



/// Implements the handle method of the FlutterPlugin interface. This method is called when invokeMethod is called on the plugin's method channel in Flutter/Dart.
/// - Parameters:
/// - call: Object that specifies the method that should be handled and the corresponding arguments
Expand All @@ -94,18 +96,16 @@ class IrmaMobileBridgePlugin: NSObject, IrmagobridgeIrmaMobileBridgeProtocol, Fl
result(nil)
}


/// Implements the DebugLog method of the IrmaMobileBridge interface.
/// - Parameter message: Message to be logged
func debugLog(_ message: String?) {
#if DEBUG
if message != nil {
NSLog("[IrmaMobileBridgePlugin] \(message)")
NSLog("[IrmaMobileBridgePlugin] \(message!)")
}
#endif
}


/// Implements the DispatchFromGo method of the IrmaMobileBridge interface.
/// - Parameters:
/// - name: name of the method being invoked
Expand Down Expand Up @@ -160,4 +160,8 @@ extension IrmaMobileBridgePlugin: FlutterApplicationLifeCycleDelegate {
}
return false
}

public func applicationWillTerminate(_ application: UIApplication) {
stop()
}
}
6 changes: 5 additions & 1 deletion lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,11 @@ class AppState extends State<App> with WidgetsBindingObserver {
),
builder: (context, snapshot) {
if (!snapshot.hasData || !_privacyScreenLoaded) {
return const SplashScreen();
// Delay the loading indicator a bit, so it doesn't flash on screen.
return FutureBuilder(
future: Future.delayed(const Duration(seconds: 3), () => true),
builder: (context, isLoading) => SplashScreen(isLoading: isLoading.data ?? false),
);
}

final displayRootedWarning = snapshot.data!.a;
Expand Down
36 changes: 23 additions & 13 deletions lib/src/screens/loading/loading_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,28 @@ class _LoadingScreenState extends State<LoadingScreen> {
}

@override
Widget build(BuildContext context) => StreamBuilder<ErrorEvent>(
stream: IrmaRepositoryProvider.of(context).getFatalErrors(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final error = snapshot.data;
return ErrorScreen.fromEvent(
error: error!,
);
}
return const SplashScreen(
isLoading: true,
Widget build(BuildContext context) {
final repo = IrmaRepositoryProvider.of(context);
return StreamBuilder<ErrorEvent>(
stream: repo.getFatalErrors().timeout(
const Duration(seconds: 15),
onTimeout: (_) => repo.dispatch(ErrorEvent(
exception: 'Timeout: enrollment status could not be determined within 15 seconds',
stack: '',
fatal: true,
)),
),
builder: (context, snapshot) {
if (snapshot.hasData) {
final error = snapshot.data;
return ErrorScreen.fromEvent(
error: error!,
);
},
);
}
return const SplashScreen(
isLoading: true,
);
},
);
}
}