๐Ÿ€ Flutter WebView ๋„์ž…๊ธฐ (2) ์›น - ํ”Œ๋Ÿฌํ„ฐํ†ต์‹ 

์ด๋„๊ฒฝยท2023๋…„ 6์›” 5์ผ
2

fRONTeND

๋ชฉ๋ก ๋ณด๊ธฐ
11/14
post-thumbnail

Flutter WebView 1ํŽธ

ํ†ต์‹ 

Web โ–ถ๏ธŽ Flutter

.addJavaScriptChannel() ๋ฅผ ํ†ตํ•ด ์›น์—์„œ ํ”Œ๋Ÿฌํ„ฐ๋กœ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋ฅผ ์œ„ํ•ด ๋ฏธ๋ฆฌ ์ž‘์„ฑํ–ˆ๋˜ ์ปจํŠธ๋กค๋Ÿฌ์— ์ฑ„๋„์„ ์„ ์–ธํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

// webview_controller.dart

..addJavaScriptChannel(
	'ChannelName',
		onMessageReceived: (JavaScriptMessage message) {
		debugPrint(message.message);
	},
)

ํ”Œ๋Ÿฌํ„ฐ์—์„œ ์ฑ„๋„์„ ๋“ฑ๋กํ•˜์˜€์œผ๋ฉด javascript๋ฅผ ํ†ตํ•ด ์ฑ„๋„์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ChannelName.postMessage('hello');

๋ฏธ๋ฆฌ ๋“ฑ๋กํ•œ ChannelName ์œผ๋กœ .postMessage(value)๋ฅผ ๋ณด๋‚ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋ถ„๋ช… ๋งŒ๋‚˜๊ฒŒ ๋  Error

ํ•˜์ง€๋งŒ javascript์—๋Š” ChannelName ์ด๋ผ๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ์œ„ํ•ด ์•„๋ž˜์˜ ์ฃผ์„์„ ์ฝ”๋“œ ์œ— ๋ถ€๋ถ„์— ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

// in javascript

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
ChannelName.postMessage('hello');

Web ํ™˜๊ฒฝ: reactJs + ts + eslint

๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋Š” ํ™˜๊ฒฝ์€ ์›น๊ณผ ํ”Œ๋Ÿฌํ„ฐ ํ™˜๊ฒฝ ๋ชจ๋‘์—์„œ ๊ตฌ๋™๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ ํ”Œ๋Ÿฌํ„ฐ์—์„œ๋งŒ ์‹คํ–‰๋˜๋„๋ก ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.
์ด๋ฅผ ์œ„ํ•ด Flutter โ–ถ๏ธŽ Web ๊ฐ„์˜ ํ†ต์‹ ์ด ํ•„์š”ํ•˜๋ฉฐ ์•„๋ž˜์˜ ๋‚ด์šฉ์— ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

Flutter โ–ถ๏ธŽ Web

ํ”Œ๋Ÿฌํ„ฐ ํ™˜๊ฒฝ์—์„œ๋Š” ์‚ฌ์ „์— ๋“ฑ๋กํ•œ ์ปจํŠธ๋กค๋Ÿฌ ํ•จ์ˆ˜๋‚ด์— javascript ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • runJavaScript()
    return ๊ฐ’์ด ์—†๋Š” ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • runJavaScriptReturningResult()
    ๋ฐ˜๋Œ€๋กœ return ๊ฐ’์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ ๊ฐ’์€ Future<String>์œผ๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ… ์ฃผ์˜!

์œ„์˜ ๋‘ ๋ฉ”์„œ๋“œ๋“ค์€ javascript root page (index.html) ์—์„œ ์‹คํ•ผํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ์ด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด reactJs์™€ ๊ฐ™์€ ํ•จ์ˆ˜์•ˆ์— ์„ ์–ธ๋œ ์ฝ”๋“œ๋“ค์€ ์‹คํ–‰ ํ•  ์ˆ˜ ์—†์—ˆ์œผ๋ฉฐ,
๋ธŒ๋ผ์šฐ์ €์˜ ์ฝ˜์†”์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ๋“ค์€ ๋Œ€๋ถ€๋ถ„ ๊ฐ€๋Šฅํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์˜ˆ์‹œ

initFlutter()
ํ”Œ๋Ÿฌํ„ฐ WebView ํ™˜๊ฒฝ์—์„œ๋งŒ Javascript ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๊ฒŒ localStorage์— ํ”Œ๋Ÿฌํ„ฐ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
getJsMessage()
return ๊ฐ’์ด ์ถ”๊ฐ€๋œ ์˜ˆ์‹œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

// webview_controller.dart

void initFlutter() {
	controller.runJavaScript('localStorage.setItem("isFlutter", "1")');
}

Future<String> getJsMessage() async {
//์›น localStorage์— ์ €์žฅํ•ด ์žˆ์„ boolean ๊ฐ’ ํ˜ธ์ถœ
	final result = await controller.runJavaScriptReturningResult(
    'JSON.parse(localStorage.getItem("storageKey"))') as String;
    print("result: $result");
	return result;
}

every code

// webview_controller.dart

//GetX๋ผ๋Š” ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ปจํŠธ๋กค๋Ÿฌ ํ™œ์šฉ
class WebviewMainController extends GetxController {
//WebviewMainController ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜
  static WebviewMainController get to => Get.find();

  //controller ๊ฐ์ฒด ์„ ์–ธ
  final WebViewController controller = WebViewController()
  
  //์ž๋ฐ”์ŠคํŠธ๋ฆฝํŠธ ์‚ฌ์šฉ ์—ฌ๋ถ€
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    //์›น๋ทฐ ๊ด€๋ จ ์ด๋ฒคํŠธ๋“ค
    ..setNavigationDelegate(
      NavigationDelegate(
        onProgress: (int progress) {
          debugPrint('progressing $progress');
        },
        onPageStarted: (String url) {
          debugPrint(url);
        },
        onPageFinished: (String url) {
          debugPrint('Page Finished');
        },
        onWebResourceError: (WebResourceError error) {},
      ),
    )
    // ๐Ÿ€ ์ถ”๊ฐ€
    ..addJavaScriptChannel(
      'ChannelName',
      onMessageReceived: (JavaScriptMessage message) {
        debugPrint(message.message);
        //... anything
      },
    )
    //์ ‘์†ํ•œ [URL]์„ ์‚ฝ์ž…
    ..loadRequest(Uri.parse([URL]));

// ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ controller๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์œ„ํ•จ
  WebViewController getController() {
    return controller;
  }

  // ๐Ÿ€ ์ถ”๊ฐ€
  void initFlutter() {
	controller.runJavaScript('localStorage.setItem("isFlutter", "1")');
  }

  Future<String> getJsMessage() async {
  //์›น localStorage์— ์ €์žฅํ•ด ์žˆ์„ boolean ๊ฐ’ ํ˜ธ์ถœ
	final result = await controller.runJavaScriptReturningResult(
    'JSON.parse(localStorage.getItem("storageKey"))') as String;
    print("result: $result");
	return result;
  }
}
// in javascript
//flutter์—์„œ๋งŒ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋„๋ก
if (localStorage.getItem("isFlutter") === "1") {
	// eslint-disable-next-line @typescript-eslint/ban-ts-comment
	//@ts-ignore
	ChannelName.postMessage(message);
}
profile
์•ˆ๋…•ํ•˜์„ธ์šฉ

4๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2023๋…„ 8์›” 24์ผ

ํ˜น์‹œ ts๊ฐ€ ์•„๋‹Œ js๋ฅผ ์“ฐ๋Š”๊ฒฝ์šฐ๋Š” ์ฃผ์„์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผํ•˜๋‚˜์š”

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2023๋…„ 10์›” 6์ผ

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
์ฃผ์„์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ด์„œ ์ปดํŒŒ์ผ ์—๋Ÿฌ๋‚œ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋ฐ, ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋„ค์š”.
ChannelName์— ๋Œ€ํ•˜์—ฌ ๋”ฐ๋กœ ์„ ์–ธํ•˜์‹  ๋ถ€๋ถ„์ด ์žˆ์œผ์‹ ๊ฐ€์š”?

1๊ฐœ์˜ ๋‹ต๊ธ€