flutter_webview_plugin.dart 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import 'dart:async';
  2. import 'package:flutter/services.dart';
  3. import 'package:flutter/material.dart';
  4. const _kChannel = 'flutter_webview_plugin';
  5. // TODO: more general state for iOS/android
  6. enum WebViewState { shouldStart, startLoad, finishLoad }
  7. // TODO: use an id by webview to be able to manage multiple webview
  8. /// Singleton Class that communicate with a Webview Instance
  9. /// Have to be instanciate after `runApp` called.
  10. class FlutterWebviewPlugin {
  11. final _channel = const MethodChannel(_kChannel);
  12. final _onDestroy = new StreamController<Null>.broadcast();
  13. final _onBackPressed = new StreamController<Null>.broadcast();
  14. final _onUrlChanged = new StreamController<String>.broadcast();
  15. final _onStateChanged = new StreamController<WebViewStateChanged>.broadcast();
  16. final _onError = new StreamController<String>.broadcast();
  17. static FlutterWebviewPlugin _instance;
  18. factory FlutterWebviewPlugin() => _instance ??= new FlutterWebviewPlugin._();
  19. FlutterWebviewPlugin._() {
  20. _channel.setMethodCallHandler(_handleMessages);
  21. }
  22. Future<Null> _handleMessages(MethodCall call) async {
  23. switch (call.method) {
  24. case "onDestroy":
  25. _onDestroy.add(null);
  26. break;
  27. case "onBackPressed":
  28. _onBackPressed.add(null);
  29. break;
  30. case "onUrlChanged":
  31. _onUrlChanged.add(call.arguments["url"]);
  32. break;
  33. case "onState":
  34. _onStateChanged.add(new WebViewStateChanged.fromMap(call.arguments));
  35. break;
  36. case "onError":
  37. _onError.add(call.arguments);
  38. break;
  39. }
  40. }
  41. /// Listening the OnDestroy LifeCycle Event for Android
  42. Stream<Null> get onDestroy => _onDestroy.stream;
  43. /// Listening url changed
  44. Stream<String> get onUrlChanged => _onUrlChanged.stream;
  45. /// Listening the onBackPressed Event for Android
  46. /// content null
  47. /// iOS WebView: worked
  48. /// android: worked
  49. Stream<Null> get onBackPressed => _onBackPressed.stream;
  50. /// Listening the onState Event for iOS WebView and Android
  51. /// content is Map for type: {shouldStart(iOS)|startLoad|finishLoad}
  52. /// more detail than other events
  53. Stream<WebViewStateChanged> get onStateChanged => _onStateChanged.stream;
  54. /// Start the Webview with [url]
  55. /// - [withJavascript] enable Javascript or not for the Webview
  56. /// iOS WebView: Not implemented yet
  57. /// - [clearCache] clear the cache of the Webview
  58. /// iOS WebView: Not implemented yet
  59. /// - [clearCookies] clear all cookies of the Webview
  60. /// iOS WebView: Not implemented yet
  61. /// - [hidden] not show
  62. /// - [fullScreen]: show in full screen mode, default true
  63. /// - [rect]: show in rect(not full screen)
  64. /// - [enableAppScheme]: false will enable all schemes, true only for httt/https/about
  65. /// android: Not implemented yet
  66. /// - [userAgent]: set the User-Agent of WebView
  67. Future<Null> launch(String url,
  68. {bool withJavascript: true,
  69. bool clearCache: false,
  70. bool clearCookies: false,
  71. bool hidden: false,
  72. bool fullScreen: true,
  73. bool enableAppScheme: true,
  74. Rect rect: null,
  75. String userAgent: null}) async {
  76. Map<String, dynamic> args = {
  77. "url": url,
  78. "withJavascript": withJavascript,
  79. "clearCache": clearCache,
  80. "hidden": hidden,
  81. "clearCookies": clearCookies,
  82. "fullScreen": fullScreen,
  83. "enableAppScheme": enableAppScheme,
  84. "userAgent": userAgent
  85. };
  86. if (!fullScreen) assert(rect != null);
  87. if (rect != null) {
  88. args["rect"] = {
  89. "left": rect.left,
  90. "top": rect.top,
  91. "width": rect.width,
  92. "height": rect.height
  93. };
  94. }
  95. await _channel.invokeMethod('launch', args);
  96. }
  97. /// Execute Javascript inside webview
  98. Future<String> evalJavascript(String code) {
  99. return _channel.invokeMethod('eval', {"code": code});
  100. }
  101. /// Close the Webview
  102. /// Will trigger the [onDestroy] event
  103. Future<Null> close() => _channel.invokeMethod("close");
  104. /// Close all Streams
  105. void dispose() {
  106. _onDestroy.close();
  107. _onBackPressed.close();
  108. _onUrlChanged.close();
  109. _onStateChanged.close();
  110. _onError.close();
  111. _instance = null;
  112. }
  113. }
  114. class WebViewStateChanged {
  115. final WebViewState type;
  116. final String url;
  117. final int navigationType;
  118. WebViewStateChanged(this.type, this.url, this.navigationType);
  119. factory WebViewStateChanged.fromMap(Map<String, dynamic> map) {
  120. WebViewState t;
  121. switch (map["type"]) {
  122. case "shouldStart":
  123. t = WebViewState.shouldStart;
  124. break;
  125. case "startLoad":
  126. t = WebViewState.startLoad;
  127. break;
  128. case "finishLoad":
  129. t = WebViewState.finishLoad;
  130. break;
  131. }
  132. return new WebViewStateChanged(t, map["url"], map["navigationType"]);
  133. }
  134. }