Masterarbeit Richard Stern. Flutter App, sich mit einem Bluetooth-Gerät verbindet und Berührungen auf einem Sensor visualisiert.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.dart 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. import 'dart:async';
  5. import 'dart:convert';
  6. import 'package:flutter/material.dart';
  7. import 'package:webview_flutter/webview_flutter.dart';
  8. void main() => runApp(MaterialApp(home: WebViewExample()));
  9. const String kNavigationExamplePage = '''
  10. <!DOCTYPE html><html>
  11. <head><title>Navigation Delegate Example</title></head>
  12. <body>
  13. <p>
  14. The navigation delegate is set to block navigation to the youtube website.
  15. </p>
  16. <ul>
  17. <ul><a href="https://www.youtube.com/">https://www.youtube.com/</a></ul>
  18. <ul><a href="https://www.google.com/">https://www.google.com/</a></ul>
  19. </ul>
  20. </body>
  21. </html>
  22. ''';
  23. class WebViewExample extends StatefulWidget {
  24. @override
  25. _WebViewExampleState createState() => _WebViewExampleState();
  26. }
  27. class _WebViewExampleState extends State<WebViewExample> {
  28. final Completer<WebViewController> _controller =
  29. Completer<WebViewController>();
  30. @override
  31. Widget build(BuildContext context) {
  32. return Scaffold(
  33. appBar: AppBar(
  34. title: const Text('Flutter WebView example'),
  35. // This drop down menu demonstrates that Flutter widgets can be shown over the web view.
  36. actions: <Widget>[
  37. NavigationControls(_controller.future),
  38. SampleMenu(_controller.future),
  39. ],
  40. ),
  41. // We're using a Builder here so we have a context that is below the Scaffold
  42. // to allow calling Scaffold.of(context) so we can show a snackbar.
  43. body: Builder(builder: (BuildContext context) {
  44. return WebView(
  45. initialUrl: 'https://flutter.dev',
  46. javascriptMode: JavascriptMode.unrestricted,
  47. onWebViewCreated: (WebViewController webViewController) {
  48. _controller.complete(webViewController);
  49. },
  50. // TODO(iskakaushik): Remove this when collection literals makes it to stable.
  51. // ignore: prefer_collection_literals
  52. javascriptChannels: <JavascriptChannel>[
  53. _toasterJavascriptChannel(context),
  54. ].toSet(),
  55. navigationDelegate: (NavigationRequest request) {
  56. if (request.url.startsWith('https://www.youtube.com/')) {
  57. print('blocking navigation to $request}');
  58. return NavigationDecision.prevent;
  59. }
  60. print('allowing navigation to $request');
  61. return NavigationDecision.navigate;
  62. },
  63. onPageFinished: (String url) {
  64. print('Page finished loading: $url');
  65. },
  66. );
  67. }),
  68. floatingActionButton: favoriteButton(),
  69. );
  70. }
  71. JavascriptChannel _toasterJavascriptChannel(BuildContext context) {
  72. return JavascriptChannel(
  73. name: 'Toaster',
  74. onMessageReceived: (JavascriptMessage message) {
  75. Scaffold.of(context).showSnackBar(
  76. SnackBar(content: Text(message.message)),
  77. );
  78. });
  79. }
  80. Widget favoriteButton() {
  81. return FutureBuilder<WebViewController>(
  82. future: _controller.future,
  83. builder: (BuildContext context,
  84. AsyncSnapshot<WebViewController> controller) {
  85. if (controller.hasData) {
  86. return FloatingActionButton(
  87. onPressed: () async {
  88. final String url = await controller.data.currentUrl();
  89. Scaffold.of(context).showSnackBar(
  90. SnackBar(content: Text('Favorited $url')),
  91. );
  92. },
  93. child: const Icon(Icons.favorite),
  94. );
  95. }
  96. return Container();
  97. });
  98. }
  99. }
  100. enum MenuOptions {
  101. showUserAgent,
  102. listCookies,
  103. clearCookies,
  104. addToCache,
  105. listCache,
  106. clearCache,
  107. navigationDelegate,
  108. }
  109. class SampleMenu extends StatelessWidget {
  110. SampleMenu(this.controller);
  111. final Future<WebViewController> controller;
  112. final CookieManager cookieManager = CookieManager();
  113. @override
  114. Widget build(BuildContext context) {
  115. return FutureBuilder<WebViewController>(
  116. future: controller,
  117. builder:
  118. (BuildContext context, AsyncSnapshot<WebViewController> controller) {
  119. return PopupMenuButton<MenuOptions>(
  120. onSelected: (MenuOptions value) {
  121. switch (value) {
  122. case MenuOptions.showUserAgent:
  123. _onShowUserAgent(controller.data, context);
  124. break;
  125. case MenuOptions.listCookies:
  126. _onListCookies(controller.data, context);
  127. break;
  128. case MenuOptions.clearCookies:
  129. _onClearCookies(context);
  130. break;
  131. case MenuOptions.addToCache:
  132. _onAddToCache(controller.data, context);
  133. break;
  134. case MenuOptions.listCache:
  135. _onListCache(controller.data, context);
  136. break;
  137. case MenuOptions.clearCache:
  138. _onClearCache(controller.data, context);
  139. break;
  140. case MenuOptions.navigationDelegate:
  141. _onNavigationDelegateExample(controller.data, context);
  142. break;
  143. }
  144. },
  145. itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
  146. PopupMenuItem<MenuOptions>(
  147. value: MenuOptions.showUserAgent,
  148. child: const Text('Show user agent'),
  149. enabled: controller.hasData,
  150. ),
  151. const PopupMenuItem<MenuOptions>(
  152. value: MenuOptions.listCookies,
  153. child: Text('List cookies'),
  154. ),
  155. const PopupMenuItem<MenuOptions>(
  156. value: MenuOptions.clearCookies,
  157. child: Text('Clear cookies'),
  158. ),
  159. const PopupMenuItem<MenuOptions>(
  160. value: MenuOptions.addToCache,
  161. child: Text('Add to cache'),
  162. ),
  163. const PopupMenuItem<MenuOptions>(
  164. value: MenuOptions.listCache,
  165. child: Text('List cache'),
  166. ),
  167. const PopupMenuItem<MenuOptions>(
  168. value: MenuOptions.clearCache,
  169. child: Text('Clear cache'),
  170. ),
  171. const PopupMenuItem<MenuOptions>(
  172. value: MenuOptions.navigationDelegate,
  173. child: Text('Navigation Delegate example'),
  174. ),
  175. ],
  176. );
  177. },
  178. );
  179. }
  180. void _onShowUserAgent(
  181. WebViewController controller, BuildContext context) async {
  182. // Send a message with the user agent string to the Toaster JavaScript channel we registered
  183. // with the WebView.
  184. controller.evaluateJavascript(
  185. 'Toaster.postMessage("User Agent: " + navigator.userAgent);');
  186. }
  187. void _onListCookies(
  188. WebViewController controller, BuildContext context) async {
  189. final String cookies =
  190. await controller.evaluateJavascript('document.cookie');
  191. Scaffold.of(context).showSnackBar(SnackBar(
  192. content: Column(
  193. mainAxisAlignment: MainAxisAlignment.end,
  194. mainAxisSize: MainAxisSize.min,
  195. children: <Widget>[
  196. const Text('Cookies:'),
  197. _getCookieList(cookies),
  198. ],
  199. ),
  200. ));
  201. }
  202. void _onAddToCache(WebViewController controller, BuildContext context) async {
  203. await controller.evaluateJavascript(
  204. 'caches.open("test_caches_entry"); localStorage["test_localStorage"] = "dummy_entry";');
  205. Scaffold.of(context).showSnackBar(const SnackBar(
  206. content: Text('Added a test entry to cache.'),
  207. ));
  208. }
  209. void _onListCache(WebViewController controller, BuildContext context) async {
  210. await controller.evaluateJavascript('caches.keys()'
  211. '.then((cacheKeys) => JSON.stringify({"cacheKeys" : cacheKeys, "localStorage" : localStorage}))'
  212. '.then((caches) => Toaster.postMessage(caches))');
  213. }
  214. void _onClearCache(WebViewController controller, BuildContext context) async {
  215. await controller.clearCache();
  216. Scaffold.of(context).showSnackBar(const SnackBar(
  217. content: Text("Cache cleared."),
  218. ));
  219. }
  220. void _onClearCookies(BuildContext context) async {
  221. final bool hadCookies = await cookieManager.clearCookies();
  222. String message = 'There were cookies. Now, they are gone!';
  223. if (!hadCookies) {
  224. message = 'There are no cookies.';
  225. }
  226. Scaffold.of(context).showSnackBar(SnackBar(
  227. content: Text(message),
  228. ));
  229. }
  230. void _onNavigationDelegateExample(
  231. WebViewController controller, BuildContext context) async {
  232. final String contentBase64 =
  233. base64Encode(const Utf8Encoder().convert(kNavigationExamplePage));
  234. controller.loadUrl('data:text/html;base64,$contentBase64');
  235. }
  236. Widget _getCookieList(String cookies) {
  237. if (cookies == null || cookies == '""') {
  238. return Container();
  239. }
  240. final List<String> cookieList = cookies.split(';');
  241. final Iterable<Text> cookieWidgets =
  242. cookieList.map((String cookie) => Text(cookie));
  243. return Column(
  244. mainAxisAlignment: MainAxisAlignment.end,
  245. mainAxisSize: MainAxisSize.min,
  246. children: cookieWidgets.toList(),
  247. );
  248. }
  249. }
  250. class NavigationControls extends StatelessWidget {
  251. const NavigationControls(this._webViewControllerFuture)
  252. : assert(_webViewControllerFuture != null);
  253. final Future<WebViewController> _webViewControllerFuture;
  254. @override
  255. Widget build(BuildContext context) {
  256. return FutureBuilder<WebViewController>(
  257. future: _webViewControllerFuture,
  258. builder:
  259. (BuildContext context, AsyncSnapshot<WebViewController> snapshot) {
  260. final bool webViewReady =
  261. snapshot.connectionState == ConnectionState.done;
  262. final WebViewController controller = snapshot.data;
  263. return Row(
  264. children: <Widget>[
  265. IconButton(
  266. icon: const Icon(Icons.arrow_back_ios),
  267. onPressed: !webViewReady
  268. ? null
  269. : () async {
  270. if (await controller.canGoBack()) {
  271. controller.goBack();
  272. } else {
  273. Scaffold.of(context).showSnackBar(
  274. const SnackBar(content: Text("No back history item")),
  275. );
  276. return;
  277. }
  278. },
  279. ),
  280. IconButton(
  281. icon: const Icon(Icons.arrow_forward_ios),
  282. onPressed: !webViewReady
  283. ? null
  284. : () async {
  285. if (await controller.canGoForward()) {
  286. controller.goForward();
  287. } else {
  288. Scaffold.of(context).showSnackBar(
  289. const SnackBar(
  290. content: Text("No forward history item")),
  291. );
  292. return;
  293. }
  294. },
  295. ),
  296. IconButton(
  297. icon: const Icon(Icons.replay),
  298. onPressed: !webViewReady
  299. ? null
  300. : () {
  301. controller.reload();
  302. },
  303. ),
  304. ],
  305. );
  306. },
  307. );
  308. }
  309. }