tagworks_sdk_flutter 1.1.5
tagworks_sdk_flutter: ^1.1.5 copied to clipboard
Official Flutter SDK for TagWorks, providing deep linking, event tracking, and user engagement features for Android and iOS.
example/lib/main.dart
import 'package:app_links/app_links.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:async';
// import 'package:tagworks_sdk_flutter/navigation/TagWorksNavigatorObserver.dart';
import 'package:flutter/services.dart';
import 'package:tagworks_sdk_flutter/tagworks_sdk_v1_flutter.dart';
import 'package:webview_flutter/webview_flutter.dart';
// late final GoRouter router;
final DeepLinkHandler deepLinkHandler = DeepLinkHandler();
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
// Future<void> main() async {
// WidgetsFlutterBinding.ensureInitialized();
// TagWorksError.install(); // 크래시 로그 자동 수집
// deepLinkHandler.start(); //
// runApp( MyApp());
// }
// class MyApp extends StatelessWidget {
// const MyApp({super.key});
// @override
// Widget build(BuildContext context) {
// return MaterialApp(
// navigatorObservers: [
// TagWorksNavigatorObserver(), // 페이지 전환 자동 수집
// ],
// initialRoute: '/',
// routes: {
// '/':(_) => const HomeScreen(),
// '/detail':(_)=> const DetailScreen(),
// },
// );
// }
// }
// 앱 진입: Zone 가드·바인딩·에러 핸들러·초기 딥링크 조회 후 runApp.
Future<void> main() async {
//
TagWorksError.runZoneGuarded(() async {
WidgetsFlutterBinding.ensureInitialized();
TagWorksError.install();
// deepLinkHandler.start();
// 앱이 링크로 "처음" 열렸을 때(백그라운드가 아닌 콜드 스타트) 한 번만 받는 초기 딥링크.
final DeeplinkResult? initial = await TagWorksDeeplinkPlugin.getInitialDeeplink();
runApp(MyApp(initial));
});
}
// 콜드 스타트 딥링크(initial)를 State로 넘겨 initState에서 라우팅.
class MyApp extends StatefulWidget {
final DeeplinkResult? initial;
const MyApp(this.initial,{super.key});
// _MyAppState에서 스트림 구독·초기 URL 라우팅 담당.
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// 앱 실행 중 이후 들어오는 딥링크(핫 스타트 등) 구독.
StreamSubscription<DeeplinkResult>? _deeplinkSub;
/// 스트림으로 들어온 딥링크 이벤트를 UI에 표시.
final TextEditingController _deeplinkStreamLogController =
TextEditingController(text: 'TagWorks 딥링크 스트림 대기 중…');
// 초기 URL postFrame 라우팅 + 플러그인 딥링크 스트림 구독.
@override
void initState() {
super.initState();
final initialUrl = widget.initial?.deeplinkURL;
final isTagWorksDeeplink = widget.initial?.isTagWorksDeeplink;
if (initialUrl != null) {
print('[deeplink] initState initialUrl=$initialUrl (postFrame에서 라우팅)');
if (isTagWorksDeeplink != null && isTagWorksDeeplink) {
// TagManager를 설정해 만든 딥링크인 경우,
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) _route(initialUrl);
});
} else {
// TagManager를 설정해 만든 딥링크인 아닌 경우, 예외 처리
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) _route(initialUrl);
});
}
// 첫 프레임 이후에 라우팅: Navigator가 MaterialApp에 붙은 뒤에 push 가능하도록.
} else {
print('[deeplink] initState 초기 URL 없음 initial=${widget.initial}');
}
// 런타임 딥링크 스트림 (앱이 이미 떠 있는 상태에서 링크로 재진입 등).
_deeplinkSub = TagWorksDeeplinkPlugin.stream.listen((event) {
print(
'[deeplink] stream event isTagWorks=${event.isTagWorksDeeplink} '
'url=${event.deeplinkURL}',
);
final head =
'${DateTime.now().toIso8601String()} $event';
final lines = [head, ..._deeplinkStreamLogController.text.split('\n')];
final capped = lines.take(30).join('\n');
if (mounted) {
setState(() {
_deeplinkStreamLogController.text = capped;
_deeplinkStreamLogController.selection =
TextSelection.collapsed(offset: 0);
});
}
final url = event.deeplinkURL;
if (url == null) return;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) _route(url);
});
});
}
// 딥링크 스트림 구독 해제.
@override
void dispose() {
_deeplinkSub?.cancel();
_deeplinkStreamLogController.dispose();
super.dispose();
}
// URL에 'prod' 포함 여부로 홈/상세로 pushNamed 분기(데모).
void _route(String url) {
final goDetail = url.contains('prod');
if (goDetail) {
navigatorKey.currentState?.pushNamed('/detail');
} else {
navigatorKey.currentState?.pushNamed('/');
}
}
// 전역 navigatorKey·옵저버·named routes로 MaterialApp 구성.
@override
Widget build(BuildContext context) {
return MaterialApp(
// 딥링크에서 Navigator에 직접 pushNamed 하기 위한 전역 키.
navigatorKey: navigatorKey,
navigatorObservers: [
TagWorksNavigatorObserver(),
],
initialRoute: '/',
routes: {
'/':(_) => const HomeScreen(),
'/detail':(_)=> const DetailScreen(),
},
builder: (context, child) {
final bottom = MediaQuery.paddingOf(context).bottom;
return Stack(
fit: StackFit.expand,
children: [
if (child != null) child,
Positioned(
left: 8,
right: 8,
bottom: 8 + bottom,
child: Material(
elevation: 8,
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.all(8),
child: TextField(
controller: _deeplinkStreamLogController,
readOnly: true,
maxLines: 5,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: 'TagWorksDeeplinkPlugin.stream',
border: OutlineInputBorder(),
isDense: true,
),
),
),
),
),
],
);
},
);
}
}
class DetailScreen extends StatelessWidget {
static const routeName = '/detail';
const DetailScreen({super.key});
// 예시 상세 화면: 앱바 + 뒤로가기 버튼.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Detail'),
),
body: Center(
child: ElevatedButton(onPressed: () {
Navigator.pop(context);
}, child: const Text('Back')),
),
);
}
}
class DeepLinkHandler {
final _appLinks = AppLinks();
StreamSubscription<Uri>? _sub;
StreamSubscription? _deeplinkSub;
String initialLocation = '/';
// app_links 스트림·초기 링크·TagWorks 이벤트 구독 시작.
void start() {
// 앱 실행 중 들어오는 링크 처리
_sub = _appLinks.uriLinkStream.listen((uri) async {
print('deeplink : ${uri}');
if (defaultTargetPlatform == TargetPlatform.android) {
await _handle(uri);
}
});
// cold start (앱이 완전히 꺼진 상태에서 링크로 실행될 때)
_appLinks.getInitialLink().then((uri) async {
print('deeplink1 : ${uri}');
if (uri != null) {
await _handle(uri);
} else {
if (defaultTargetPlatform == TargetPlatform.android) {
final deferred = await TagWorksDeeplinkPlugin.handleDeferredDeeplink();
if (deferred.isTagWorksDeeplink && deferred.deeplinkURL != null) {
initialLocation = deferred.deeplinkURL!;
print('deeplink deferred : ${initialLocation}');
}
}
}
}).catchError((_) {});
// 딥링크 처리 후 TagWorks로부터 랜딩페이지 파라미터 전달
_deeplinkSub = TagWorksDeeplinkPlugin.stream.listen((event) {
debugPrint('HomePage에서만 딥링크 처리: $event');
});
}
// URI를 플러그인에 넘겨 TagWorks 딥링크 결과만 로그(Android 위주).
Future<void> _handle(Uri uri) async {
try {
final result = await TagWorksDeeplinkPlugin.handleDeeplinkWithUri(uri.toString());
if (result.isTagWorksDeeplink && result.deeplinkURL != null) {
print('deeplink final: ${result.deeplinkURL}');
}
} catch (e) {
// 예외 발생 시 처리
print('딥링크 처리 중 오류 발생: $e');
}
}
// app_links 및 TagWorks 이벤트 구독 취소.
void dispose() {
_sub?.cancel();
_deeplinkSub?.cancel();
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
// 웹뷰·초기화 버튼 등 예제 UI 상태는 _HomeScreen에서 관리.
@override
State<HomeScreen> createState() => _HomeScreen();
}
class _HomeScreen extends State<HomeScreen> {
String _platformVersion = 'Unknown';
String? bannerUrl;
late final WebViewController _controller;
String _messageFromWeb = "";
// StreamSubscription? _sub;
// String? _latestLink;
// WebView 채널·네비게이션 델리게이트 설정 후 데모 URL 로드.
@override
void initState() {
super.initState();
// 웹뷰 테스트
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
// ..runJavaScript("""
// window.__TAGWORKS_SDK_READY = true;
// """)
..addJavaScriptChannel(
TagWorksPlugin.TAGWORKS_WEBVIEW_CHANNEL,
// "TagWorksFT_JSInterfaces",
onMessageReceived: (JavaScriptMessage message) async {
setState(() {
_messageFromWeb = message.message;
});
print("웹뷰 인터페이스 받은 메시지: ${_messageFromWeb}");
await TagWorksPlugin.webInterfaceDidReceive(_messageFromWeb);
},
)
..setNavigationDelegate(
NavigationDelegate(
onPageFinished: (String url) async {
debugPrint("✅ 페이지 로딩 완료: $url");
await _controller.runJavaScript(
TagWorksPlugin.TAGWORKS_WEBVIEW_ADD_SCRIPT
);
// await _controller.runJavaScript("""
// window.__TAGWORKS_SDK_READY = true;
// """);
},
),
)
..loadRequest(Uri.parse("https://dxlab.obzen.com/html/bnk/BNK_Main.html"));
// ..loadRequest(Uri.parse("http://192.168.20.53/g5/shop/"));
// ..loadRequest(Uri.parse("http://192.168.24.185/rshop"));
}
// Flutter로 메시지 보내기
// TagWorksJSInterface.postMessage("Hello from WebView!");
// 예제에서 공유한 DeepLinkHandler 리소스 정리.
@override
void dispose() {
// _sub?.cancel();
deepLinkHandler.dispose();
super.dispose();
}
// Platform messages are asynchronous, so we initialize in an async method.
// TagWorks 초기화·CMS·WebView 등 플러그인 데모 UI.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(children: [
Expanded(
child: ElevatedButton(
onPressed: () async {
try {
await TagWorksPlugin.initializeTagWorks(
siteId: "165,b1VTZzuL",
baseUrl: "https://dxlab.obzen.com/tagworks/obzen",
isUseIntervals: false,
dispatchIntervalWithSeconds: 5,
sessionTimeOutWithSeconds: 5,
isManualDispatch: false,
// "dispatchRetryCount": 3,
appVersion: "1.5",
appName: "testapp",
isUseDynamicParameter: true,
deeplinkServerUrl: "https://dxlab.obzen.com/ozsmlinkg",
autoTrackingPage: true,
autoTrackingApplication: false,
);
//print('초기화$result');
final isInitialized = await TagWorksPlugin.isInitialize();
await TagWorksPlugin.enableTestTool(true);
await TagWorksPlugin.setLogLevel(3);
await TagWorksPlugin.setOptOut(false);
await TagWorksPlugin.setUserId('ny2060');
final visitorId = await TagWorksPlugin.getVisitorId();
print('visitorId : ${visitorId}');
// final siteId = await TagWorksPlugin().getSiteId();
// print('siteId:${siteId}');
await TagWorksPlugin.setCommonDimensionWithString(3, '계좌관리');
await TagWorksPlugin.setCommonDimensionWithDouble(1, 00.9);
await TagWorksPlugin.setCommonDimensionWithDouble(11, 3.8888);
await TagWorksPlugin.setDynamicCommonDimensionWithString("사용자행동01", '계좌이체');
await TagWorksPlugin.setDynamicCommonDimensionWithDouble("사용자행동02", 50000.0);
final commonDimensions = await TagWorksPlugin.getCommonDimensions();
print('공용 디멘젼 : $commonDimensions');
final dynamicCommonDimensions = await TagWorksPlugin.getDynamicCommonDimensions();
print('공용 동적 디멘젼 : $dynamicCommonDimensions');
final commonDimensionsOfArray = await TagWorksPlugin.getCommonDimensionsOfArrayIndex();
print('공용 dimensionsOfArray : ${commonDimensionsOfArray}');
final dynamicCommonDimensionsOfArray = await TagWorksPlugin.getDynamicCommonDimensionsOfArrayIndex();
print('공용 동적 dimensionsOfArray : ${dynamicCommonDimensionsOfArray}');
final dim01 = await TagWorksPlugin.getCommonDimensionWithString(3);
print('공용 General : $dim01');
final dim02 = await TagWorksPlugin.getCommonDimensionWithDouble(11);
print('공용 Fact : $dim02');
final dim03 = await TagWorksPlugin.getDynamicCommonDimension("사용자행동01");
print('공용 동적 General : $dim03');
// await TagWorksPlugin().removeCommonDimensionInGeneralType(3);
await TagWorksPlugin.removeCommonDimensionInFactType(1);
// await TagWorksPlugin().removeCommonDimensionWithArrayIndex(1);
print('공통 디멘젼 : ${await TagWorksPlugin.getCommonDimensions()}');
// await TagWorksPlugin().removeAllCommonDimension();
// print('공통:${await TagWorksPlugin().getCommonDimensions()}');
await TagWorksPlugin.setCommonDimensionWithString(4, '통장');
await TagWorksPlugin.setCommonDimensionWithDouble(1, 3333.9);
await TagWorksPlugin.setCommonDimensionWithDouble(11, 99.00);
await TagWorksPlugin.sendReferrerEventWithOpenUrlString("https://www.naver.com");
/**
* dataBundle
*/
await DataBundlePlugin.initialize();
//await DataBundlePlugin.initDataBundle(null);
// print(DataBundlePlugin.);
await DataBundlePlugin.putString(DataBundlePlugin.EVENT_TAG_NAME, StandardEvent.PAGE_VIEW);
await DataBundlePlugin.putString(DataBundlePlugin.EVENT_TAG_PARAM_PAGE_PATH, '/페이지경로');
await DataBundlePlugin.putString(DataBundlePlugin.EVENT_TAG_PARAM_TITLE, '페이지타이틀');
await DataBundlePlugin.putString(DataBundlePlugin.EVENT_TAG_PARAM_KEYWORD, '검색어');
await DataBundlePlugin.putString(DataBundlePlugin.EVENT_TAG_PARAM_CUSTOM_PATH, '/커스텀경로');
await DataBundlePlugin.putDimensionWithString(1, "계좌신청");
await DataBundlePlugin.putDimensionWithDouble(2, 0.999);
await DataBundlePlugin.putDynamicDimensionWithString("사용자행동11", "계좌조회");
await DataBundlePlugin.putDynamicDimensionWithDouble("사용자행동22", 998877);
final dimensions = await DataBundlePlugin.getDimensions();
print('개별 : ${dimensions} ');
final dynamicDimensions = await DataBundlePlugin.getDynamicDimensions();
print('개별 동적 : ${dynamicDimensions} ');
final arrayDimensions = await DataBundlePlugin.getDimensionsOfArrayIndex();
print('개별 arrayIndex : ${arrayDimensions} ');
final arrayDynamicDimensions = await DataBundlePlugin.getDynamicDimensionsOfArrayIndex();
print('개별 동적 arrayIndex : ${arrayDynamicDimensions} ');
final dataBundle = await DataBundlePlugin.getDataBundle();
print('getDataBundle: ${dataBundle} ');
await DataBundlePlugin.initDataBundle(dataBundle);
/**
* logEvent
*/
await TagWorksPlugin.logEvent(TagWorksPlugin.EVENT_TYPE_PAGE, dataBundle);
} catch (e) {
print('Failed to initialize TagWorks: $e');
}
},
child: Text('Initialize TagWorks'),
)),
const SizedBox(height: 16),
// === 새로 추가한 onCMS Popup 버튼 ===
Expanded(
child: ElevatedButton(
onPressed: () async {
try {
await TagWorksPopupPlugin.onCMSPopup(
onCmsUrl: 'https://dxlab.obzen.com/oncms',
rcmdAreaCd: 'POPUP_TEST_AREA',
custId: '',
);
print('onCMS Popup 호출 성공');
} catch (e) {
print('onCMS Popup 호출 실패: $e');
}
},
child: const Text('Show CMS Popup'),
)),
Expanded(
child: ElevatedButton(
onPressed: () async {
// JavaScript 실행
await _controller.runJavaScript("""
if (window.__TAGWORKS_SDK_READY) {
window.TagWorksFT_JSInterfaces.postMessage("ABV");
}
""");
},
child: const Text('JSInterface Test'),
)),
const SizedBox(width: 8),
// ⭐ 추가 버튼
Expanded(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/detail');
},
child: const Text('화면 이동'),
),
),
]),
const SizedBox(height: 24),
Text('CMS Banner', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(
height: 200, // ★ 꼭 사이즈를 주세요(없으면 0으로 안 보임)
width: double.infinity,
child: OnCmsBannerWidget(
onCmsUrl: 'https://dxlab.obzen.com/oncms',
rcmdAreaCd: 'BANNER_OBZ_AREA',
custId: '', // 필요 없으면 null
defaultImage: 'ic_banner_placeholder', // drawable에 넣어둔 이름
),
),
// webview 테스트
const SizedBox(height: 4),
// WebView
const Text('WebView', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(
height: 500, // 웹뷰 화면 높이 지정
child: WebViewWidget(controller: _controller),
),
],
),
),
),
);
}
}