프로그래밍/flutter

[flutter] Flutter에서 홈 화면 앱 위젯 웹뷰 메뉴 바로가기 방법 (안드로이드)

소행성왕자 2023. 11. 14. 17:18

목적 : 홈 화면의 위젯에서 바로가기 메뉴 클릭시 웹뷰의 메뉴 이동

개념도

홈화면 위젯에서 버튼 클릭시 아래와 같은 순서로 실행됩니다.

홈화면 위젯에서 버튼 클릭 -> WidgetProvider -> flutter(main.dart)

WidgetProvider 에서는 홈위젯의 어떤 메뉴가 클릭되었는지 확인합니다.

해결되지 않았던부분이 menu1 클릭시 앱이 화면에 보여줘야 되는데 안보이고 내부 데이터만 보여진 부분입니다.

이때의 코드는 아래와 같습니다.

수정전

val backgroundIntentMenu1 = HomeWidgetBackgroundIntent.getBroadcast(context,
    Uri.parse("myAppWidget://updatecountermenu1"))
setOnClickPendingIntent(R.id.bt_menu1, backgroundIntentMenu1)

수정후

val backgroundIntentMenu1 = HomeWidgetLaunchIntent.getActivity(
    context,
    MainActivity::class.java,
    Uri.parse("myAppWidget://updatecountermenu1")
);
setOnClickPendingIntent(R.id.bt_menu1, backgroundIntentMenu1)
HomeWidgetLaunchIntent.getActivity 호출해야 하는데 
HomeWidgetBackgroundIntent.getBroadcast 호출 원인입니다.

HomeWidgetLaunchIntent.getActivity: HomeWidgetLaunchIntent 클래스의 getActivity 메서드를 호출하여 PendingIntent를 생성합니다. 

이 메서드는 주어진 액티비티를 실행하는 PendingIntent를 반환합니다.

context: 현재 컨텍스트를 나타냅니다. 

액티비티나 서비스 등에서 제공되는 컨텍스트입니다.

MainActivity::class.java: 실행할 액티비티의 클래스를 지정합니다. 

여기서는 MainActivity입니다.

Uri.parse("myAppWidget://updatecountermenu1"): Intent에 추가할 URI를 지정합니다. 

이 URI는 특정 동작 또는 데이터를 식별하는 데 사용됩니다. 

여기서 "myAppWidget://updatecountermenu1"은 사용자 정의 스킴인 "myAppWidget"을 가진 URI입니다. 

이는 나중에 해당 URI로 전달된 데이터를 처리하는 데 사용됩니다.

setOnClickPendingIntent: 위젯의 레이아웃에서 특정 뷰(여기서는 R.id.bt_menu1)에 대한 클릭 이벤트에 대한 PendingIntent를 설정합니다.

R.id.bt_menu1: 클릭 이벤트를 설정할 위젯의 뷰 ID입니다. 

이 경우에는 bt_menu1이라는 뷰의 ID를 나타냅니다.

backgroundIntentMenu1: 앞서 생성한 PendingIntent입니다. 

이 PendingIntent는 bt_menu1이 클릭될 때 실행되는 동작을 정의합니다. 

여기서는 MainActivity를 실행하는 Intent입니다.

즉, 이 코드는 bt_menu1이라는 버튼이 클릭될 때 MainActivity를 실행하는 PendingIntent를 설정하는 역할을 합니다.

 

그렇다면 이제 실제 myAppWidget URI 가지고 main.dart 의 어떤 부분이 실행될까요?

보통 backgroundCallback 함수가 호출되는데 backgroundCallback 호출되면 실제 webviewController 에 접근이 안됩니다.

그래서 backgroundCallback 함수를 class _WebViewAppState extends State<WebViewApp> 안에 정의 합니다.

main.dart

class _WebViewAppState extends State<WebViewApp> {
  late WebViewController controller;
  
  @override
  void initState() {
    super.initState();

    WebViewControllerManager webViewControllerManager = WebViewControllerManager();
    controller = webViewControllerManager.getIns();

    HomeWidget.registerBackgroundCallback(homeWidgetBackgroundCallback);
    HomeWidget.widgetClicked.listen((uri) => loadData(uri));
  }

late WebViewController controller;: _WebViewAppState 클래스에 속하는 WebViewController 변수를 선언합니다. 

이 컨트롤러는 웹 뷰의 동작을 제어하고 상태를 관리하는 데 사용됩니다. 

late 키워드는 나중에 초기화되는 변수임을 나타냅니다.

initState 메서드: 위젯이 생성될 때 호출되는 생명 주기 메서드 중 하나입니다. 

super.initState()를 호출하여 부모 클래스의 initState를 실행한 후에 추가적인 초기화를 진행합니다.

WebViewControllerManager webViewControllerManager = WebViewControllerManager();: WebViewControllerManager 클래스의 인스턴스를 생성합니다. 

이 클래스는 웹 뷰 컨트롤러를 관리하는데 사용됩니다.

controller = webViewControllerManager.getIns();

: 위에서 생성한 WebViewControllerManager 인스턴스를 통해 웹 뷰 컨트롤러를 가져와 controller 변수에 할당합니다.

HomeWidget.registerBackgroundCallback(homeWidgetBackgroundCallback);

: 홈 위젯의 백그라운드 콜백을 등록합니다. 

이 콜백은 홈 위젯이 백그라운드에서 실행될 때 호출되는 함수를 지정합니다.

HomeWidget.widgetClicked.listen((uri) => loadData(uri));

: HomeWidget에서 제공하는 widgetClicked 스트림을 구독합니다. 

이 스트림은 위젯이 클릭될 때 발생하는 이벤트를 수신할 수 있도록 합니다. 

클릭된 URI에 대해 loadData 함수를 호출합니다.

총괄적으로 보면, 이 코드는 웹 뷰 컨트롤러를 초기화하고, 홈 위젯의 백그라운드 콜백 및 클릭 이벤트에 대한 처리를 설정하는 부분입니다.

 

다음 코드는 homeWidgetBackgroundCallback 함수로, 홈 위젯이 백그라운드에서 실행될 때 호출되는 콜백 함수입니다.

주어진 Uri 매개변수를 기반으로 특정 동작을 수행합니다.

@pragma("vm:entry-point")
  void homeWidgetBackgroundCallback(Uri? uri) async {

    WebViewControllerManager webViewControllerManager = WebViewControllerManager();

    print(">>>>>backgroundCallback");
    print(uri?.host);


    // 1번 위젯
    if (uri?.host == 'updatecounter') {

      // 스타루트 페이지 가지고오 C110816
      String html = await fetchPrdCd();
      // fetch page 를 분석
      Map<String, dynamic> parsedPrdcdJson = fetchSplit(html);

      var prdcdSell = parsedPrdcdJson['USDKRW']['sell'];
      var prdcdBuy = parsedPrdcdJson['USDKRW']['buy'];

      print("fetch 숫자 Sell: $prdcdSell");
      print("fetch 숫자 Buy : $prdcdBuy");

      int _counter = 0;
      await HomeWidget.getWidgetData<int>('_counter', defaultValue: 0)
          .then((int? value) {
        _counter = value ?? 0;
        _counter++;
      });

      await HomeWidget.saveWidgetData<String>('_prdcdSell', prdcdSell);
      await HomeWidget.saveWidgetData<String>('_prdcdBuy', prdcdBuy);

      await HomeWidget.saveWidgetData<int>('_counter', _counter);
      await HomeWidget.updateWidget(name: 'AppWidgetProvider', iOSName: 'AppWidgetProvider');
    }
    else if (uri?.host == 'updatecounterlarge') {

      // 스타루트 페이지 가지고오 C110816
      String html = await fetchPrdCd();
      // fetch page 를 분석
      Map<String, dynamic> parsedPrdcdJson = fetchSplit(html);

      var prdcdSell = parsedPrdcdJson['USDKRW']['sell'];
      var prdcdBuy = parsedPrdcdJson['USDKRW']['buy'];

      print("fetch 숫자 Sell: $prdcdSell");
      print("fetch 숫자 Buy : $prdcdBuy");

      int _counter = 0;
      await HomeWidget.getWidgetData<int>('_counter', defaultValue: 0)
          .then((int? value) {
        _counter = value ?? 0;
        _counter++;
      });

      await HomeWidget.saveWidgetData<String>('_prdcdSell', prdcdSell);
      await HomeWidget.saveWidgetData<String>('_prdcdBuy', prdcdBuy);

      await HomeWidget.saveWidgetData<int>('_counter', _counter);
      await HomeWidget.updateWidget(name: 'AppWidgetProviderLarge', iOSName: 'AppWidgetProviderLarge');

    }
    else if (uri?.host == 'updatecountermenu1') {
      print("============= menu1");
      // 새로운 URL 설정
      controller.loadRequest(Uri.parse("http://ar.com/?110641"));

    }
    else if (uri?.host == 'updatecountermenu2') {
      print("============= menu2");
      controller.loadRequest(Uri.parse("http://ar.com/?110630"));
    }
    else if (uri?.host == 'updatecountermenu3') {
      print("============= menu3");
      controller.loadRequest(Uri.parse("http://ar.com/?110624"));
    }
  }


WebViewControllerManager webViewControllerManager = WebViewControllerManager();

: WebViewControllerManager 클래스의 인스턴스를 생성합니다. 

이 클래스는 웹 뷰 컨트롤러를 관리하는데 사용됩니다.

print(">>>>>backgroundCallback"); 

print(uri?.host);

: 콜백이 실행되었음을 알리는 디버깅 출력과 함께, 전달된 Uri의 호스트를 출력합니다.

if (uri?.host == 'updatecounter') { ... }

: URI의 호스트가 'updatecounter'인 경우, 특정 작업을 수행합니다. 

주로 fetchPrdCd 함수를 호출하여 데이터를 가져오고, 해당 데이터를 가공하여 홈 위젯에 업데이트하고자 하는 것입니다.

else if (uri?.host == 'updatecountermenu1') { ... }

: URI의 호스트가 'updatecountermenu1'인 경우, 특정 URL로 웹 뷰의 페이지를 로드하도록 합니다. 


else if (uri?.host == 'updatecountermenu2') { ... }, else if (uri?.host == 'updatecountermenu3') { ... }

: 'updatecountermenu2' 및 'updatecountermenu3'에 대해서도 각각 다른 URL을 로드하도록 설정되어 있습니다.

이러한 방식으로 homeWidgetBackgroundCallback 함수는 URI의 호스트에 따라 다양한 작업을 수행하고, 웹 뷰의 내용을 업데이트하거나 특정 URL로 이동하는 등의 동작을 수행합니다.