Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое Deeplink
Определение
Deeplink - это специальная ссылка, которая открывает приложение и ведёт пользователя прямо на нужный экран, минуя главную страницу. Это похоже на обычные веб-ссылки, но для мобильных приложений.
Примеры deeplinks
Обычная ссылка:
https://example.com/products/123
Deeplink приложения:
myapp://products/123
или
https://example.com/products/123 (Universal Link / App Link)
Типы deeplinks
1. Custom Scheme Deeplinks (старый способ)
myapp://products/123
myapp://user/john@example.com
myapp://open?screen=settings&theme=dark
Проблема: браузер не знает, существует ли приложение с таким схемой. Может показать ошибку.
2. Universal Links (iOS) и App Links (Android) - новый способ
https://example.com/products/123
https://example.com/user/john
Преимущество: если приложение не установлено, ссылка откроется в браузере и покажет веб-версию.
Реализация в Flutter
Шаг 1: Настройка iOS
// ios/Runner/Info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.example.myapp</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
Шаг 2: Настройка Android
<!-- android/app/src/main/AndroidManifest.xml -->
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Custom Scheme -->
<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:scheme="myapp" />
</intent-filter>
</activity>
Шаг 3: Обработка deeplinks в Flutter
import 'package:uni_links/uni_links.dart';
import 'package:uni_links_web/uni_links_web.dart';
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late StreamSubscription deepLinkSubscription;
final navigatorKey = GlobalKey<NavigatorState>();
@override
void initState() {
super.initState();
_initDeepLinkListener();
}
void _initDeepLinkListener() {
// Слушаем входящие deeplinks пока приложение в памяти
deepLinkSubscription = uriLinkStream.listen(
(String? link) {
if (link != null) {
_handleDeepLink(link);
}
},
onError: (err) {
print('Deep link error: $err');
},
);
// Проверяем, если приложение было запущено с deeplink
_checkInitialDeepLink();
}
Future<void> _checkInitialDeepLink() async {
try {
final initialLink = await getInitialUri();
if (initialLink != null) {
_handleDeepLink(initialLink.toString());
}
} catch (e) {
print('Error getting initial link: $e');
}
}
void _handleDeepLink(String link) {
print('Handling deeplink: $link');
// Парсим ссылку
final uri = Uri.parse(link);
if (uri.scheme == 'myapp') {
// Обработка custom scheme deeplinks
final path = uri.path; // /products/123
final id = uri.pathSegments.last; // 123
navigatorKey.currentState?.pushNamed(
'/products',
arguments: ProductArgs(id: id),
);
} else if (uri.host == 'example.com') {
// Обработка universal links
final pathSegments = uri.pathSegments;
if (pathSegments.first == 'products') {
final id = pathSegments.last;
navigatorKey.currentState?.pushNamed(
'/products',
arguments: ProductArgs(id: id),
);
} else if (pathSegments.first == 'user') {
final username = pathSegments.last;
navigatorKey.currentState?.pushNamed(
'/user',
arguments: UserArgs(username: username),
);
}
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
home: HomePage(),
onGenerateRoute: (settings) {
// Роутинг приложения
if (settings.name == '/products') {
final args = settings.arguments as ProductArgs;
return MaterialPageRoute(
builder: (_) => ProductDetailScreen(productId: args.id),
);
}
return null;
},
);
}
@override
void dispose() {
deepLinkSubscription.cancel();
super.dispose();
}
}
class ProductArgs {
final String id;
ProductArgs({required this.id});
}
Практические примеры
Приглашение в чат:
myapp://chat/room_id_123
myapp://chat/room_id_123?invite_code=ABC123
Поделиться профилем:
myapp://user/john_doe
https://example.com/user/john_doe
Специальное предложение:
myapp://promo?code=SUMMER20&discount=30
https://example.com/promo/SUMMER20
Тестирование deeplinks
На iOS:
# Эмулятор
xcrun simctl openurl booted "myapp://products/123"
# Реальное устройство
ios-deploy -b /path/to/app.app -o /path/to/app --args "myapp://products/123"
На Android:
# Эмулятор или устройство
adb shell am start -W -a android.intent.action.VIEW -d "myapp://products/123" com.example.myapp
Из браузера: Просто напечатай deeplink в адресную строку:
myapp://products/123
Advanced: Dynamic Links (Firebase)
Для более сложных сценариев используй Firebase Dynamic Links:
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
FirebaseDynamicLinks dynamicLinks = FirebaseDynamicLinks.instance;
void initDynamicLinks() async {
dynamicLinks.onLink.listen(
(PendingDynamicLinkData? dynamicLinkData) async {
final Uri deepLink = dynamicLinkData?.link ?? Uri.parse('');
if (deepLink.path.isNotEmpty) {
_handleDeepLink(deepLink.toString());
}
},
onError: (e) async {
print('Dynamic Links error: ${e.message}');
},
);
// Получить первоначальный dynamic link
final PendingDynamicLinkData? initialLink =
await dynamicLinks.getInitialLink();
if (initialLink?.link != null) {
_handleDeepLink(initialLink!.link.toString());
}
}
Преимущества deeplinks
- User Experience - пользователь попадает прямо на контент
- Marketing - можно делиться прямыми ссылками в соцсетях
- Analytics - отслеживаешь, откуда приходят пользователи
- Реф программы - друзья приглашают друзей по deeplinks
Best practices
- Обработай случаи, когда deeplink невалиден
- Если приложение не установлено - перенаправь на веб-версию
- Тестируй на реальных устройствах - поведение может отличаться
- Используй универсальные ссылки - надёжнее, чем custom schemes
- Документируй все deeplinks - для команды и маркетинга