shyun_link 2.2.1
shyun_link: ^2.2.1 copied to clipboard
Complete deeplink and short URL management with native platform integration. Ultra-simple ShyunLinkManager API, Android/iOS native setup included, Clean Architecture, and enterprise-grade error handling.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shyun_link/shyun_link.dart';
/**
* ShyunLink Complete Example App
*
* 이 예제는 ShyunLinkManager의 모든 기능을 보여줍니다:
* - 울트라 심플 초기화 (5줄로 완성)
* - 딥링크 자동 처리
* - 짧은 링크 생성 및 공유
* - 배치 처리
* - 네이티브 딥링크 연동
*/
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 🎉 ShyunLinkManager로 5줄 초기화!
await ShyunLinkManager.initialize(
appScheme: 'nearound',
webBaseUrl: 'https://cocl.nearound.co',
apiServerUrl: 'https://www.nearound.co',
shortLinkDomain: 'near.ly',
onDeepLink: (context) {
print('🔗 딥링크 받음: ${context.pageType}, ID: ${context.pageId}');
// 실제 앱에서는 Navigator.pushNamed() 또는 Get.toNamed() 사용
_handleDeepLink(context);
},
);
runApp(ShyunLinkExampleApp());
}
// 딥링크 처리 함수
void _handleDeepLink(DeepLinkContext context) {
print('📱 딥링크 처리: ${context.toString()}');
// 실제 앱에서는 이런 식으로 구현:
// switch (context.pageType) {
// case 'store':
// Get.toNamed('/storeDetail', parameters: {'id': context.pageId.toString()});
// break;
// case 'curation':
// Get.toNamed('/curationDetail', parameters: {
// 'id': context.pageId.toString(),
// 'type': context.params['type'] ?? 'default',
// });
// break;
// default:
// Get.toNamed(context.route);
// break;
// }
}
class ShyunLinkExampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ShyunLink Complete Example',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final MethodChannel _nativeChannel = MethodChannel('shyun_link_example/deeplink');
String _lastShortLink = 'None';
String _systemStatus = 'Loading...';
List<String> _testResults = [];
@override
void initState() {
super.initState();
_updateSystemStatus();
_setupNativeDeepLinkListener();
}
// 네이티브 딥링크 리스너 설정
void _setupNativeDeepLinkListener() {
_nativeChannel.setMethodCallHandler((call) async {
if (call.method == 'onDeepLink') {
final String deepLink = call.arguments;
print('📱 네이티브에서 딥링크 받음: $deepLink');
// ShyunLinkManager로 처리
await ShyunLinkManager.processDeepLink(deepLink);
setState(() {
_testResults.insert(0, '✅ 네이티브 딥링크: $deepLink');
if (_testResults.length > 10) _testResults.removeLast();
});
}
});
}
void _updateSystemStatus() {
final status = ShyunLinkManager.getSystemStatus();
setState(() {
_systemStatus = status != null
? 'ShyunLink 활성화됨 (${status['shortLinkRepository']})'
: 'ShyunLink 비활성화됨';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ShyunLink Complete Example'),
elevation: 0,
),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildStatusCard(),
SizedBox(height: 16),
_buildSimpleApiSection(),
SizedBox(height: 16),
_buildConvenienceSection(),
SizedBox(height: 16),
_buildBatchSection(),
SizedBox(height: 16),
_buildTestingSection(),
SizedBox(height: 16),
_buildTestResults(),
],
),
),
);
}
Widget _buildStatusCard() {
return Card(
color: Colors.blue[50],
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.info, color: Colors.blue),
SizedBox(width: 8),
Text(
'ShyunLink v2.2.1',
style: Theme.of(context).textTheme.titleLarge,
),
],
),
SizedBox(height: 8),
Text('상태: $_systemStatus'),
SizedBox(height: 4),
Text('마지막 생성 링크: $_lastShortLink'),
SizedBox(height: 12),
Text(
'✨ v2.2.1: 완전한 네이티브 플랫폼 통합! 📱',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.green[700],
),
),
],
),
),
);
}
Widget _buildSimpleApiSection() {
return Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'🚀 Ultra-Simple API',
style: Theme.of(context).textTheme.titleLarge,
),
SizedBox(height: 8),
Text('ShyunLinkManager로 간단하게 링크 생성'),
SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton(
onPressed: () => _createSimpleStoreLink(),
child: Text('스토어 링크'),
),
ElevatedButton(
onPressed: () => _createSimpleCurationLink(),
child: Text('큐레이션 링크'),
),
ElevatedButton(
onPressed: () => _createSimpleEventLink(),
child: Text('이벤트 링크'),
),
ElevatedButton(
onPressed: () => _createCustomLink(),
child: Text('커스텀 링크'),
),
],
),
],
),
),
);
}
Widget _buildConvenienceSection() {
return Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'📤 편의 공유 기능',
style: Theme.of(context).textTheme.titleLarge,
),
SizedBox(height: 8),
Text('링크 생성 + 공유를 한번에'),
SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton.icon(
onPressed: () => _shareStore(),
icon: Icon(Icons.store),
label: Text('스토어 공유'),
),
ElevatedButton.icon(
onPressed: () => _shareCuration(),
icon: Icon(Icons.article),
label: Text('큐레이션 공유'),
),
ElevatedButton.icon(
onPressed: () => _shareEvent(),
icon: Icon(Icons.event),
label: Text('이벤트 공유'),
),
ElevatedButton.icon(
onPressed: () => _shareApp(),
icon: Icon(Icons.mobile_friendly),
label: Text('앱 홍보'),
),
],
),
],
),
),
);
}
Widget _buildBatchSection() {
return Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'📦 배치 처리',
style: Theme.of(context).textTheme.titleLarge,
),
SizedBox(height: 8),
Text('여러 링크를 한번에 생성'),
SizedBox(height: 16),
ElevatedButton.icon(
onPressed: _createBatchLinks,
icon: Icon(Icons.list),
label: Text('배치 링크 생성 (5개)'),
),
],
),
),
);
}
Widget _buildTestingSection() {
return Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'🧪 딥링크 테스트',
style: Theme.of(context).textTheme.titleLarge,
),
SizedBox(height: 8),
Text('네이티브와 Flutter 딥링크 테스트'),
SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton(
onPressed: () => _testCustomScheme(),
child: Text('nearound:// 테스트'),
),
ElevatedButton(
onPressed: () => _testHttpsLink(),
child: Text('HTTPS 링크 테스트'),
),
ElevatedButton(
onPressed: () => _testShortLink(),
child: Text('짧은 링크 테스트'),
),
ElevatedButton(
onPressed: () => _checkInitialLink(),
child: Text('초기 링크 확인'),
),
],
),
],
),
),
);
}
Widget _buildTestResults() {
if (_testResults.isEmpty) return SizedBox.shrink();
return Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'📋 테스트 결과',
style: Theme.of(context).textTheme.titleLarge,
),
SizedBox(height: 8),
Container(
height: 200,
child: ListView.builder(
itemCount: _testResults.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 2),
child: Text(
_testResults[index],
style: TextStyle(
fontSize: 12,
fontFamily: 'monospace',
),
),
);
},
),
),
TextButton(
onPressed: () => setState(() => _testResults.clear()),
child: Text('결과 지우기'),
),
],
),
),
);
}
// ================================
// Simple API Methods
// ================================
Future<void> _createSimpleStoreLink() async {
try {
final link = await ShyunLinkManager.createShortLink(
type: 'store',
id: 12345,
metadata: {'source': 'example_app'},
);
setState(() {
_lastShortLink = link ?? 'Failed';
_testResults.insert(0, '✅ 스토어 링크: $link');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar('스토어 링크 생성: $link', isSuccess: true);
} catch (e) {
_showSnackBar('스토어 링크 생성 실패: $e');
}
}
Future<void> _createSimpleCurationLink() async {
try {
final link = await ShyunLinkManager.createShortLink(
type: 'curation',
id: 456,
metadata: {
'curation_type': 'banner',
'source': 'example_app',
},
);
setState(() {
_lastShortLink = link ?? 'Failed';
_testResults.insert(0, '✅ 큐레이션 링크: $link');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar('큐레이션 링크 생성: $link', isSuccess: true);
} catch (e) {
_showSnackBar('큐레이션 링크 생성 실패: $e');
}
}
Future<void> _createSimpleEventLink() async {
try {
final link = await ShyunLinkManager.createShortLink(
type: 'event',
id: 789,
metadata: {'source': 'example_app'},
);
setState(() {
_lastShortLink = link ?? 'Failed';
_testResults.insert(0, '✅ 이벤트 링크: $link');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar('이벤트 링크 생성: $link', isSuccess: true);
} catch (e) {
_showSnackBar('이벤트 링크 생성 실패: $e');
}
}
Future<void> _createCustomLink() async {
try {
final link = await ShyunLinkManager.createShortLink(
type: 'giftcode',
code: 'EXAMPLE2024',
metadata: {
'campaign': 'app_example',
'source': 'example_app',
},
);
setState(() {
_lastShortLink = link ?? 'Failed';
_testResults.insert(0, '✅ 기프트 링크: $link');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar('기프트 링크 생성: $link', isSuccess: true);
} catch (e) {
_showSnackBar('기프트 링크 생성 실패: $e');
}
}
// ================================
// Convenience Share Methods
// ================================
Future<void> _shareStore() async {
final success = await ShyunLinkManager.shareStore(
12345,
customText: '🏪 맛집 추천! 꼭 가보세요!',
);
setState(() {
_testResults.insert(0, success ? '✅ 스토어 공유 성공' : '❌ 스토어 공유 실패');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar(success ? '스토어 공유 완료!' : '스토어 공유 실패', isSuccess: success);
}
Future<void> _shareCuration() async {
final success = await ShyunLinkManager.shareCuration(
456,
'banner',
customText: '📋 이 큐레이션을 확인해보세요!',
);
setState(() {
_testResults.insert(0, success ? '✅ 큐레이션 공유 성공' : '❌ 큐레이션 공유 실패');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar(success ? '큐레이션 공유 완료!' : '큐레이션 공유 실패', isSuccess: success);
}
Future<void> _shareEvent() async {
final success = await ShyunLinkManager.shareEvent(
789,
customText: '🎉 특별한 이벤트를 놓치지 마세요!',
);
setState(() {
_testResults.insert(0, success ? '✅ 이벤트 공유 성공' : '❌ 이벤트 공유 실패');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar(success ? '이벤트 공유 완료!' : '이벤트 공유 실패', isSuccess: success);
}
Future<void> _shareApp() async {
final success = await ShyunLinkManager.shareApp(
customText: '📱 우리 앱을 다운로드해보세요!',
);
setState(() {
_testResults.insert(0, success ? '✅ 앱 홍보 성공' : '❌ 앱 홍보 실패');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar(success ? '앱 홍보 완료!' : '앱 홍보 실패', isSuccess: success);
}
// ================================
// Batch Operations
// ================================
Future<void> _createBatchLinks() async {
try {
final requests = [
LinkRequest.store(1),
LinkRequest.store(2),
LinkRequest.curation(100, 'banner'),
LinkRequest.event(50),
LinkRequest.giftCode('BATCH123'),
];
final links = await ShyunLinkManager.createBatchLinks(requests);
setState(() {
_testResults.insert(0, '✅ 배치 링크 ${links.length}개 생성');
for (int i = 0; i < links.length && i < 5; i++) {
_testResults.insert(0, ' ${i+1}. ${links[i]}');
}
while (_testResults.length > 15) _testResults.removeLast();
});
_showSnackBar('배치 링크 ${links.length}개 생성 완료!', isSuccess: true);
} catch (e) {
_showSnackBar('배치 링크 생성 실패: $e');
}
}
// ================================
// Deep Link Testing
// ================================
Future<void> _testCustomScheme() async {
final testUrl = 'nearound://store/12345';
try {
await _nativeChannel.invokeMethod('testDeepLink', {'url': testUrl});
setState(() {
_testResults.insert(0, '✅ Custom Scheme 테스트: $testUrl');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar('Custom Scheme 딥링크 테스트 완료', isSuccess: true);
} catch (e) {
_showSnackBar('Custom Scheme 테스트 실패: $e');
}
}
Future<void> _testHttpsLink() async {
final testUrl = 'https://cocl.nearound.co/curationDetail?type=banner&id=456';
try {
await _nativeChannel.invokeMethod('testDeepLink', {'url': testUrl});
setState(() {
_testResults.insert(0, '✅ HTTPS 링크 테스트: $testUrl');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar('HTTPS 딥링크 테스트 완료', isSuccess: true);
} catch (e) {
_showSnackBar('HTTPS 링크 테스트 실패: $e');
}
}
Future<void> _testShortLink() async {
final testUrl = 'https://near.ly/abc123';
try {
await _nativeChannel.invokeMethod('testDeepLink', {'url': testUrl});
setState(() {
_testResults.insert(0, '✅ 짧은 링크 테스트: $testUrl');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar('짧은 링크 테스트 완료', isSuccess: true);
} catch (e) {
_showSnackBar('짧은 링크 테스트 실패: $e');
}
}
Future<void> _checkInitialLink() async {
try {
final initialLink = await _nativeChannel.invokeMethod('getInitialLink');
setState(() {
_testResults.insert(0, '✅ 초기 링크: ${initialLink ?? "없음"}');
if (_testResults.length > 10) _testResults.removeLast();
});
_showSnackBar(
initialLink != null
? '초기 링크: $initialLink'
: '초기 링크 없음',
isSuccess: true,
);
} catch (e) {
_showSnackBar('초기 링크 확인 실패: $e');
}
}
void _showSnackBar(String message, {bool isSuccess = false}) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: isSuccess ? Colors.green : Colors.red,
duration: Duration(seconds: 3),
),
);
}
}