iku*_*rek 7 android deep-linking ios flutter flutter-navigation
我正在使用带有嵌套路由器的 Flutter Navigator 2.0 - 有一个通过调用创建的主路由器,MaterialApp.router()以及使用适当的 RouterDelegates 创建为小部件的子路由器Router()(子路由器用作底部导航的页面)。
在当前的用例中,我想使用深层链接打开嵌套路由器内的页面之一,因此我按照说明进行配置:
RouteInformationParser将其解析为我自己的模型PlatformRouteInformationProvider通知所有嵌套路由器有关路由更改的信息当应用程序位于前台时(在启动屏幕上),一切正常 - 我收到一个 PushRoute 事件,并且根和嵌套Router小部件正确处理深层链接。但是,当应用程序未启动时,我没有收到设置为我的深层链接的初始路由,并且我得到默认值,空RouteInformation即空。为什么会发生这种情况?这是我的代码示例:
Android Manifest 中的FlutterMainActivity配置:
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- For deeplinking -->
<meta-data
android:name="flutter_deeplinking_enabled"
android:value="true" />
<!-- Accepts links in format myapp://*.myapp.com/ -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="*.myapp.com"
android:scheme="myapp" />
</intent-filter>
</activity>
Run Code Online (Sandbox Code Playgroud)
主应用程序类(在 RunApp 中使用):
class MyApp extends StatelessWidget {
static PlatformRouteInformationProvider routeInformationProvider =
PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation(),
);
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => FutureBuilder(
future: AppInit.initApp(),
builder: (context, snapshot) {
return _app();
},
);
Widget _app() => MultiRepositoryProvider(
providers: AppRepositoryProviders().list,
child: MultiBlocProvider(
providers: AppBlocProviders().list,
child: MaterialApp.router(
supportedLocales: LocalizationConfig.supportedLocales,
localizationsDelegates: LocalizationConfig.localizationDelegates,
theme: LightTheme().themeData,
routerDelegate: UserSessionRouter(),
routeInformationParser: AppRouteInformationParser(),
routeInformationProvider: routeInformationProvider,
backButtonDispatcher: RootBackButtonDispatcher(),
),
),
);
...
}
Run Code Online (Sandbox Code Playgroud)
RouteInformationParser 实现:
class AppRouteInformationParser extends RouteInformationParser<DeepLinkRoute> {
@override
Future<DeepLinkRoute> parseRouteInformation(
RouteInformation routeInformation) async {
if (routeInformation.location.isNullOrEmpty) {
return DeepLinkRoute.none();
} else {
return DeepLinkParser.parse(routeInformation.location!).fold(
(data) => DeepLinkRoute(
link: data,
route: _getRouteFromDeeplink(data),
),
(error) => DeepLinkRoute.none(),
);
}
}
RouteDefinition _getRouteFromDeeplink(DeepLink deepLink) {
switch (deepLink.path) {
case '/auth/signup':
return AppRoutes.authSignup;
default:
return AppRoutes.none;
}
}
@override
RouteInformation restoreRouteInformation(DeepLinkRoute configuration) =>
RouteInformation(
location: configuration.link.path,
state: configuration.link.queryParams,
);
}
Run Code Online (Sandbox Code Playgroud)
带有嵌套(子)路由器的屏幕:
class AuthScreen extends StatefulWidget {
const AuthScreen({Key? key}) : super(key: key);
@override
_AuthScreenState createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
final AuthRouter _routerDelegate = AuthRouter();
ChildBackButtonDispatcher? _backButtonDispatcher;
@override
void didChangeDependencies() {
_initBackButtonDispatcher();
super.didChangeDependencies();
}
void _initBackButtonDispatcher() {
_backButtonDispatcher ??=
ChildBackButtonDispatcher(context.router.backButtonDispatcher!);
_backButtonDispatcher?.takePriority();
}
@override
Widget build(BuildContext context) => MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => SigninScreenCubit(
usersRepository: context.read<UsersRepository>(),
))
],
child: Router(
routerDelegate: _routerDelegate,
backButtonDispatcher: _backButtonDispatcher,
routeInformationParser: AppRouteInformationParser(),
routeInformationProvider:
MyApp.routeInformationProvider,
),
);
}
Run Code Online (Sandbox Code Playgroud)
我用这个命令测试深度链接:
adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "$1"
Run Code Online (Sandbox Code Playgroud)
对于给定的类,启动应用程序时的深层链接始终为空。我最好的猜测是RouteInformationProvider:
static PlatformRouteInformationProvider routeInformationProvider =
PlatformRouteInformationProvider(initialRouteInformation: const RouteInformation());
Run Code Online (Sandbox Code Playgroud)
或者某种配置错误,但我自己无法识别。
更新:
我在 iOS 上对此进行了测试,令人惊讶的是,它的工作原理与 Android 完全相反 - 当应用程序被终止时,它可以通过深层链接正常打开,但当它在前台时永远Router不会更新,RouteInformationProvider并且RouteInformationParser两者都不会被调用。我在 Flutter GitHub 存储库上发现了一些相关问题,虽然它们已关闭,但我认为它们不能解决我的问题。这个问题似乎与我的问题几乎相同,但我查看了应该解决它的 PR,我可以看到其他用户也报告了 iOS 上的深层链接问题。
发生这种情况是因为routeInformationProvider当应用程序刚刚打开时,您正在使用空路由覆盖该值,而不是从操作系统接收正确的路由。
将空值更改routeInformationProvider为导航器默认实际使用的值。
static PlatformRouteInformationProvider routeInformationProvider =
PlatformRouteInformationProvider(
initialRouteInformation: RouteInformation(
location: PlatformDispatcher.instance.defaultRouteName),
);
Run Code Online (Sandbox Code Playgroud)
请记住,您需要导入dart:ui.
这将使用 Android 和 iOS 的特定行为来在启动应用程序时读取深层链接路由,因为它从操作系统接收路由。
但这并不能解决 iOS 问题。
| 归档时间: |
|
| 查看次数: |
3084 次 |
| 最近记录: |