diff --git a/example/lib/main.dart b/example/lib/main.dart index f594c99..0ba0f2b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -135,6 +135,20 @@ class HomePage extends StatelessWidget { }, child: Text('新网络请求'), ), + RaisedButton( + onPressed: () { + Navigator.push(context, MaterialPageRoute(builder: (_) { + return TaobaoImageLoader( + 'https://h5.m.taobao.com/app/detail/desc.html?_isH5Des=true#!id=592787622422&type=1&f=&sellerType=B', + onImagesLoad: (images) { + Logger.debug(images.toString()); + }, + ); + })); + // TaobaoUtil.getImage(); + }, + child: Text('抓淘宝图片'), + ), ], ), ), diff --git a/example/pubspec.lock b/example/pubspec.lock index be0a1f1..c3863ca 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -721,6 +721,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" + webview_flutter: + dependency: transitive + description: + name: webview_flutter + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.22+1" xdg_directories: dependency: transitive description: diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 230c5ff..fe47ab7 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -8,18 +8,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:zhiying_comm_example/main.dart'; - void main() { testWidgets('Verify Platform version', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); // Verify that platform version is retrieved. expect( find.byWidgetPredicate( - (Widget widget) => widget is Text && - widget.data.startsWith('Running on:'), + (Widget widget) => + widget is Text && widget.data.startsWith('Running on:'), ), findsOneWidget, ); diff --git a/lib/util/encode_util.dart b/lib/util/encode_util.dart index 0cff747..cab1dfd 100644 --- a/lib/util/encode_util.dart +++ b/lib/util/encode_util.dart @@ -26,7 +26,8 @@ class EncodeUtil { * Base64解密 */ static String decodeBase64(String data) { - return String.fromCharCodes(base64Decode(data)); + // return String.fromCharCodes(base64Decode(data)); + return utf8.decode(base64Decode(data)); } // 图片转成base64 diff --git a/lib/util/taobao/taobao_image_loader.dart b/lib/util/taobao/taobao_image_loader.dart new file mode 100644 index 0000000..04f0875 --- /dev/null +++ b/lib/util/taobao/taobao_image_loader.dart @@ -0,0 +1,89 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; +import 'package:zhiying_comm/zhiying_comm.dart'; + +class TaobaoImageLoader extends StatefulWidget { + final String url; + String script; + final ValueChanged> onImagesLoad; + + TaobaoImageLoader(this.url, {Key key, this.script, this.onImagesLoad}) + : super(key: key) { + this.script = script; + if (EmptyUtil.isEmpty(this.script)) { + this.script = + 'CnZhciB6cj17fTsKZnVuY3Rpb24gZ2V0aW4oc3RyMSxzdHIyLHN0cjMpewogICAgc3RyMT1zdHIxKycnO3N0cjI9c3RyMisnJztzdHIzPXN0cjMrJyc7CiAgICB2YXIgdG1wPXN0cjEuc3BsaXQoc3RyMik7CiAgICBpZih0bXBbMV09PW51bGwpdG1wWzFdPScnOwogICAgdG1wPXRtcFsxXS5zcGxpdChzdHIzKTsKICAgIHJldHVybiB0bXBbMF07Cn0KZnVuY3Rpb24gY2hlY2soKXsKICAgIC8qenIudG1wPWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdkZXNjcmlwdGlvbicpLmlubmVySFRNTDsqLwogICAgenIudG1wPWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdKX2Z1bGxDb250ZW50JykuaW5uZXJIVE1MOwogICAgaWYoenIudG1wPT1udWxsfHx6ci50bXA9PScnfHx6ci50bXAuaW5kZXhPZigiLmpwZyIpPT0tMSl7CiAgICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKXtjaGVjaygpO30sMzAwKTsKICAgICAgICByZXR1cm47CiAgICB9CiAgICB6ci5hbGw9enIudG1wLnNwbGl0KCdzcmM9Jyk7CiAgICB6ci5yZXR1cm5fZGF0YT1bXTsKICAgIHpyLm49LTE7CiAgICBmb3IodmFyIGkgPSAwLGxlbiA9IHpyLmFsbC5sZW5ndGg7IGkgPCBsZW47IGkrKyl7CiAgICAgICAgaWYoaT09MCljb250aW51ZTsKICAgICAgICBpZih6ci5hbGwubGVuZ3RoLTE9PWkpY29udGludWU7CiAgICAgICAgenIudG1wdmFsPXpyLmFsbFtpXTsKICAgICAgICB6ci50bXB2YWw9Z2V0aW4oenIudG1wdmFsLCciJywnIicpOwogICAgICAgIGlmKHpyLnRtcHZhbC5pbmRleE9mKCJiYXNlNjQiKSE9LTF8fHpyLnRtcHZhbC5pbmRleE9mKCJocmVmPSIpIT0tMSljb250aW51ZTsKICAgICAgICBpZih6ci50bXB2YWwuaW5kZXhPZigiaHR0cCIpPT0tMSl6ci50bXB2YWw9Imh0dHBzOiIrenIudG1wdmFsOwogICAgICAgIHpyLm4rKzsKICAgICAgICB6ci5yZXR1cm5fZGF0YVt6ci5uXT16ci50bXB2YWw7CiAgICB9CiAgICB6ci5yZXR1cm5fZGF0YT1KU09OLnN0cmluZ2lmeSh6ci5yZXR1cm5fZGF0YSk7CiAgICAvLyBkb2N1bWVudC5ib2R5LmlubmVySFRNTD16ci5yZXR1cm5fZGF0YTsKICAgIExvYWRlci5wb3N0TWVzc2FnZSh6ci5yZXR1cm5fZGF0YSk7CiAgICAvLyBqaCh6ci5yZXR1cm5fZGF0YSwiIik7Cn0KdHJ5e3dpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7Y2hlY2soKTt9LDApO30KY2F0Y2goZXJyKXtkb2N1bWVudC5ib2R5LmlubmVySFRNTD1KU09OLnN0cmluZ2lmeShlcnIpO30KCg=='; + } + } + + @override + _TaobaoImageLoaderState createState() => _TaobaoImageLoaderState(); +} + +class _TaobaoImageLoaderState extends State { + WebViewController _webViewController; + + List _images = []; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('抓取淘宝详情图'), + ), + // We're using a Builder here so we have a context that is below the Scaffold + // to allow calling Scaffold.of(context) so we can show a snackbar. + body: Builder(builder: (BuildContext context) { + return WebView( + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + onWebViewCreated: (WebViewController webViewController) { + _webViewController = webViewController; + }, + // TODO(iskakaushik): Remove this when collection literals makes it to stable. + // ignore: prefer_collection_literals + javascriptChannels: [ + _imageLoaderJavascriptChannel(context), + ].toSet(), + navigationDelegate: (NavigationRequest request) { + print('allowing navigation to $request'); + return NavigationDecision.navigate; + }, + onPageStarted: (String url) { + print('Page started loading: $url'); + }, + onPageFinished: (String url) { + _loadImages(); + }, + gestureNavigationEnabled: true, + ); + }), + ); + } + + void _loadImages() { + String js = EncodeUtil.decodeBase64(widget.script); + _webViewController.evaluateJavascript(js).then((result) {}); + } + + JavascriptChannel _imageLoaderJavascriptChannel(BuildContext context) { + return JavascriptChannel( + name: 'Loader', + onMessageReceived: (JavascriptMessage message) { + if (widget.onImagesLoad != null) { + List list = jsonDecode(message.message); + if (list.length != _images.length) { + Future.delayed(Duration(milliseconds: 1000), () { + _loadImages(); + }); + _images = list.map((item) => item.toString()).toList(); + widget.onImagesLoad(_images); + } else { + print('图片抓取结束'); + } + } + }); + } +} diff --git a/lib/zhiying_comm.dart b/lib/zhiying_comm.dart index 2e2af93..59cbc8c 100644 --- a/lib/zhiying_comm.dart +++ b/lib/zhiying_comm.dart @@ -19,6 +19,8 @@ export 'util/empty_util.dart'; export 'util/global_config.dart'; export 'util/api.dart'; +export 'util/taobao/taobao_image_loader.dart'; + // 用户信息 export 'models/user/user_info_model.dart'; export 'models/user/user_info_model_notifier.dart'; diff --git a/pubspec.lock b/pubspec.lock index e8bf921..bcedffb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -714,6 +714,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.22+1" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ba9a5e2..47767a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,6 +31,7 @@ dependencies: flutter_bloc: ^4.0.1 # 骨架屏 shimmer: ^1.1.1 + webview_flutter: ^0.3.22+1 dev_dependencies: