improve app link banner handling

This commit is contained in:
Fabian Freund
2026-08-09 05:19:35 +02:00
parent 599fb997f1
commit 54e277be72
14 changed files with 3334 additions and 4620 deletions
+78 -123
View File
@@ -10,9 +10,9 @@ import 'package:flutter/services.dart';
import 'package:meta/meta.dart' show immutable, protected, visibleForTesting;
Object? _extractReplyValueOrThrow(
List<Object?>? replyList,
String channelName, {
required bool isNullValid,
List<Object?>? replyList,
String channelName, {
required bool isNullValid,
}) {
if (replyList == null) {
throw PlatformException(
@@ -34,11 +34,8 @@ Object? _extractReplyValueOrThrow(
return replyList.firstOrNull;
}
List<Object?> wrapResponse({
Object? result,
PlatformException? error,
bool empty = false,
}) {
List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty = false}) {
if (empty) {
return <Object?>[];
}
@@ -47,7 +44,6 @@ List<Object?> wrapResponse({
}
return <Object?>[error.code, error.message, error.details];
}
bool _deepEquals(Object? a, Object? b) {
if (identical(a, b)) {
return true;
@@ -60,9 +56,8 @@ bool _deepEquals(Object? a, Object? b) {
}
if (a is List && b is List) {
return a.length == b.length &&
a.indexed.every(
((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]),
);
a.indexed
.every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]));
}
if (a is Map && b is Map) {
if (a.length != b.length) {
@@ -111,29 +106,23 @@ int _deepHash(Object? value) {
return value.hashCode;
}
/// Transport types for Tor connections
enum TransportType {
/// Direct Tor connection (no bridges)
none,
/// obfs4 pluggable transport
obfs4,
/// Snowflake pluggable transport (default broker)
snowflake,
/// Snowflake via AMP cache
snowflakeAmp,
/// Meek pluggable transport
meek,
/// Meek via Azure CDN
meekAzure,
/// WebTunnel pluggable transport
webtunnel,
/// Custom bridge lines (passthrough)
custom,
}
@@ -174,8 +163,7 @@ class TorConfiguration {
}
Object encode() {
return _toList();
}
return _toList(); }
static TorConfiguration decode(Object result) {
result as List<Object?>;
@@ -197,11 +185,7 @@ class TorConfiguration {
if (identical(this, other)) {
return true;
}
return _deepEquals(transport, other.transport) &&
_deepEquals(bridgeLines, other.bridgeLines) &&
_deepEquals(entryNodeCountries, other.entryNodeCountries) &&
_deepEquals(exitNodeCountries, other.exitNodeCountries) &&
_deepEquals(strictNodes, other.strictNodes);
return _deepEquals(transport, other.transport) && _deepEquals(bridgeLines, other.bridgeLines) && _deepEquals(entryNodeCountries, other.entryNodeCountries) && _deepEquals(exitNodeCountries, other.exitNodeCountries) && _deepEquals(strictNodes, other.strictNodes);
}
@override
@@ -250,8 +234,7 @@ class TorStatus {
}
Object encode() {
return _toList();
}
return _toList(); }
static TorStatus decode(Object result) {
result as List<Object?>;
@@ -273,11 +256,7 @@ class TorStatus {
if (identical(this, other)) {
return true;
}
return _deepEquals(isRunning, other.isRunning) &&
_deepEquals(socksPort, other.socksPort) &&
_deepEquals(bootstrapProgress, other.bootstrapProgress) &&
_deepEquals(currentCircuit, other.currentCircuit) &&
_deepEquals(exitNodeCountry, other.exitNodeCountry);
return _deepEquals(isRunning, other.isRunning) && _deepEquals(socksPort, other.socksPort) && _deepEquals(bootstrapProgress, other.bootstrapProgress) && _deepEquals(currentCircuit, other.currentCircuit) && _deepEquals(exitNodeCountry, other.exitNodeCountry);
}
@override
@@ -308,12 +287,15 @@ class TorLogMessage {
int timestamp;
List<Object?> _toList() {
return <Object?>[severity, message, timestamp];
return <Object?>[
severity,
message,
timestamp,
];
}
Object encode() {
return _toList();
}
return _toList(); }
static TorLogMessage decode(Object result) {
result as List<Object?>;
@@ -333,9 +315,7 @@ class TorLogMessage {
if (identical(this, other)) {
return true;
}
return _deepEquals(severity, other.severity) &&
_deepEquals(message, other.message) &&
_deepEquals(timestamp, other.timestamp);
return _deepEquals(severity, other.severity) && _deepEquals(message, other.message) && _deepEquals(timestamp, other.timestamp);
}
@override
@@ -348,6 +328,7 @@ class TorLogMessage {
}
}
class _PigeonCodec extends StandardMessageCodec {
const _PigeonCodec();
@override
@@ -355,16 +336,16 @@ class _PigeonCodec extends StandardMessageCodec {
if (value is int) {
buffer.putUint8(4);
buffer.putInt64(value);
} else if (value is TransportType) {
} else if (value is TransportType) {
buffer.putUint8(129);
writeValue(buffer, value.index);
} else if (value is TorConfiguration) {
} else if (value is TorConfiguration) {
buffer.putUint8(130);
writeValue(buffer, value.encode());
} else if (value is TorStatus) {
} else if (value is TorStatus) {
buffer.putUint8(131);
writeValue(buffer, value.encode());
} else if (value is TorLogMessage) {
} else if (value is TorLogMessage) {
buffer.putUint8(132);
writeValue(buffer, value.encode());
} else {
@@ -396,10 +377,8 @@ class TorApi {
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
TorApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
: pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty
? '.$messageChannelSuffix'
: '';
: pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
final BinaryMessenger? pigeonVar_binaryMessenger;
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
@@ -409,30 +388,27 @@ class TorApi {
/// Start Tor with the given configuration
/// Returns a Future to avoid blocking the main thread
Future<int> startTor(TorConfiguration config) async {
final pigeonVar_channelName =
'dev.flutter.pigeon.flutter_tor.TorApi.startTor$pigeonVar_messageChannelSuffix';
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.startTor$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
<Object?>[config],
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[config]);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: false,
);
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: false,
)
;
return pigeonVar_replyValue! as int;
}
/// Stop Tor
Future<void> stopTor() async {
final pigeonVar_channelName =
'dev.flutter.pigeon.flutter_tor.TorApi.stopTor$pigeonVar_messageChannelSuffix';
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.stopTor$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
@@ -442,16 +418,16 @@ class TorApi {
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
_extractReplyValueOrThrow(
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: true,
);
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: true,
)
;
}
/// Get current status
Future<TorStatus> getStatus() async {
final pigeonVar_channelName =
'dev.flutter.pigeon.flutter_tor.TorApi.getStatus$pigeonVar_messageChannelSuffix';
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.getStatus$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
@@ -461,17 +437,17 @@ class TorApi {
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: false,
);
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: false,
)
;
return pigeonVar_replyValue! as TorStatus;
}
/// Request a new Tor identity (new circuit)
Future<void> requestNewIdentity() async {
final pigeonVar_channelName =
'dev.flutter.pigeon.flutter_tor.TorApi.requestNewIdentity$pigeonVar_messageChannelSuffix';
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.TorApi.requestNewIdentity$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
@@ -481,10 +457,11 @@ class TorApi {
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
_extractReplyValueOrThrow(
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: true,
);
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: true,
)
;
}
}
@@ -498,20 +475,12 @@ abstract class TorLogApi {
/// Called when status changes
void onStatusChanged(TorStatus status);
static void setUp(
TorLogApi? api, {
BinaryMessenger? binaryMessenger,
String messageChannelSuffix = '',
}) {
messageChannelSuffix = messageChannelSuffix.isNotEmpty
? '.$messageChannelSuffix'
: '';
static void setUp(TorLogApi? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
{
final pigeonVar_channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.flutter_tor.TorLogApi.onLogMessage$messageChannelSuffix',
pigeonChannelCodec,
binaryMessenger: binaryMessenger,
);
'dev.flutter.pigeon.flutter_tor.TorLogApi.onLogMessage$messageChannelSuffix', pigeonChannelCodec,
binaryMessenger: binaryMessenger);
if (api == null) {
pigeonVar_channel.setMessageHandler(null);
} else {
@@ -523,20 +492,16 @@ abstract class TorLogApi {
return wrapResponse(empty: true);
} on PlatformException catch (e) {
return wrapResponse(error: e);
} catch (e) {
return wrapResponse(
error: PlatformException(code: 'error', message: e.toString()),
);
} catch (e) {
return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
}
});
}
}
{
final pigeonVar_channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.flutter_tor.TorLogApi.onStatusChanged$messageChannelSuffix',
pigeonChannelCodec,
binaryMessenger: binaryMessenger,
);
'dev.flutter.pigeon.flutter_tor.TorLogApi.onStatusChanged$messageChannelSuffix', pigeonChannelCodec,
binaryMessenger: binaryMessenger);
if (api == null) {
pigeonVar_channel.setMessageHandler(null);
} else {
@@ -548,10 +513,8 @@ abstract class TorLogApi {
return wrapResponse(empty: true);
} on PlatformException catch (e) {
return wrapResponse(error: e);
} catch (e) {
return wrapResponse(
error: PlatformException(code: 'error', message: e.toString()),
);
} catch (e) {
return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
}
});
}
@@ -563,13 +526,9 @@ class IPtProxyController {
/// Constructor for [IPtProxyController]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
IPtProxyController({
BinaryMessenger? binaryMessenger,
String messageChannelSuffix = '',
}) : pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty
? '.$messageChannelSuffix'
: '';
IPtProxyController({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
: pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
final BinaryMessenger? pigeonVar_binaryMessenger;
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
@@ -577,43 +536,39 @@ class IPtProxyController {
final String pigeonVar_messageChannelSuffix;
Future<int> start(TransportType proxyType, String proxy) async {
final pigeonVar_channelName =
'dev.flutter.pigeon.flutter_tor.IPtProxyController.start$pigeonVar_messageChannelSuffix';
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.IPtProxyController.start$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
<Object?>[proxyType, proxy],
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[proxyType, proxy]);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: false,
);
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: false,
)
;
return pigeonVar_replyValue! as int;
}
Future<void> stop(TransportType proxyType) async {
final pigeonVar_channelName =
'dev.flutter.pigeon.flutter_tor.IPtProxyController.stop$pigeonVar_messageChannelSuffix';
final pigeonVar_channelName = 'dev.flutter.pigeon.flutter_tor.IPtProxyController.stop$pigeonVar_messageChannelSuffix';
final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
<Object?>[proxyType],
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[proxyType]);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
_extractReplyValueOrThrow(
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: true,
);
pigeonVar_replyList,
pigeonVar_channelName,
isNullValid: true,
)
;
}
}