{"id":87,"date":"2022-02-07T13:34:41","date_gmt":"2022-02-07T05:34:41","guid":{"rendered":"http:\/\/iichen.cn\/?p=87"},"modified":"2022-02-07T13:34:41","modified_gmt":"2022-02-07T05:34:41","slug":"flutter","status":"publish","type":"post","link":"https:\/\/iichen.cn\/?p=87","title":{"rendered":"Flutter-\u57fa\u7c7b\u5c01\u88c5"},"content":{"rendered":"<h3>1.  \u9875\u9762\u57fa\u7c7b<\/h3>\n<blockquote><p>\n  \u652f\u6301\u7f51\u7edc\u65ad\u5f00\u540e\u91cd\u8bd5\u3001\u4effAndroid\u751f\u547d\u5468\u671f\n<\/p><\/blockquote>\n<pre><code class=\"language-dart line-numbers\">    import 'dart:async';\n    import 'package:flutter\/material.dart';\n    import 'package:flutter\/services.dart';\n    import 'package:flutter_basic\/flutter_biz_widgets.dart';\n    import 'package:flutter_basic\/flutter_http_dio.dart';\n    import 'package:connectivity\/connectivity.dart';\n    import 'package:flutter_basic\/flutter_utils.dart';\n    abstract class BasePage extends StatefulWidget {\n      const BasePage({ Key key }) : super(key: key);\n\n      @override\n      BasePageState createState() =&gt; getState();\n\n      \/\/\/\u5b50\u7c7b\u5b9e\u73b0\n      BasePageState getState();\n    }\n\n    abstract class BasePageState&lt;T extends BasePage&gt; extends State&lt;T&gt; with RouteAware,WidgetsBindingObserver{\n      CancelToken cancelToken;\n\n      \/\/ \u8bb0\u5f55\u5f53\u524d\u7f51\u7edc\u72b6\u6001 \u5982\uff1a\u5f53\u524d\u7f51\u7edc\u672a\u94fe\u63a5\uff0c\u4e00\u5b9a\u65f6\u95f4\u540e\uff0c\u7f51\u7edc\u6062\u590d\u540e\u9700\u8981\u62c9\u8d77\u91cd\u65b0\u94fe\u63a5 \u6b64\u4e3a\u6807\u8bc6\u7b26\n      String networkStatus;\n\n      final Connectivity _connectivity = Connectivity();\n\n      StreamSubscription&lt;ConnectivityResult&gt; _connectivitySubscription;\n\n      \/\/ \u4f18\u5316\n      AppLifecycleState lastState;\n      bool isPause = false;\n\n      \/\/\u7f51\u7edc\u521d\u59cb\u72b6\u6001\n      netListener() {\n        _connectivitySubscription =\n            _connectivity.onConnectivityChanged.listen((ConnectivityResult result) {\n              if(networkStatus==ConnectivityResult.none.toString() &amp;&amp; result!=ConnectivityResult.none){\n                retry();\n              }\n              networkStatus = result.toString();\n            });\n      }\n\n      \/\/ \u5224\u65ad\u7f51\u7edc\u662f\u5426\u53ef\u7528\n      bool isNetValid(){\n        return networkStatus==ConnectivityResult.none.toString();\n      }\n\n      Future&lt;bool&gt; checkNetConnect() async {\n        var connectivityResult = await (_connectivity.checkConnectivity());\n        if (connectivityResult == ConnectivityResult.mobile) {\n          return true;\n        }\n        return false;\n      }\n\n      \/\/\u7f51\u7edc\u7ed3\u675f\u76d1\u542c\n      connectivityDispose() {\n        _connectivitySubscription.cancel();\n      }\n\n      \/\/\u7f51\u7edc\u8fdb\u884c\u76d1\u542c\n      Future&lt;Null&gt; initConnectivity() async {\n        \/\/\u5e73\u53f0\u6d88\u606f\u53ef\u80fd\u4f1a\u5931\u8d25\uff0c\u56e0\u6b64\u6211\u4eec\u4f7f\u7528Try\/Catch PlatformException\u3002\n        try {\n          networkStatus = (await _connectivity.checkConnectivity()).toString();\n          netListener();\n        } on PlatformException catch (e) {\n          print(e.toString());\n          networkStatus = 'Failed to get connectivity.';\n        }\n      }\n\n      @override\n      void initState() {\n        initConnectivity();\n        cancelToken = CancelToken();\n        onCreate();\n        super.initState();\n      }\n\n      @override\n      void dispose() {\n        cancelToken?.cancel(\"\u9875\u9762\u9500\u6bc1\uff0c\u7f51\u7edc\u8bf7\u6c42\u81ea\u52a8\u5173\u95ed\uff01\");\n        connectivityDispose();\n        Future.delayed(Duration(milliseconds: 300));\n        onDestroy();\n        super.dispose();\n        IIRouteObserver.instance.unsubscribe(this);\n        WidgetsBinding.instance.removeObserver(this);\n      }\n\n      @override\n      Widget build(BuildContext context) {\n      }\n\n      \/\/ \u7f51\u7edc\u4ece\u4e0d\u53ef\u7528\u5230\u53ef\u7528\u65f6 \u8fdb\u884c\u56de\u8c03 \u53ef\u4ee5\u7528\u4e8e\u5237\u65b0\u6570\u636e\n      void retry(){}\n\n      @override\n      void didPushNext() {\n        isPause = true;\n        onPause();\n      }\n\n      @override\n      void didPop() {\n        onStop();\n      }\n\n      @override\n      void didPopNext() {\n        isPause = false;\n        onReStart();\n      }\n\n      @override\n      void didChangeAppLifecycleState(AppLifecycleState state) {\n        \/\/ \u524d\u53f0\u5230\u540e\u53f0  inactive-&gt;paused\n        \/\/ \u540e\u53f0\u5230\u524d\u53f0  resumed\n        if(lastState!=state &amp;&amp; !isPause){\n          lastState = state;\n          if (state == AppLifecycleState.resumed) {\n            onReStart();\/\/ onResume(); \u4e5f\u884c   onReStart\u6bd4\u8f83\u5408\u9002 \u56e0\u4e3a\u5148\u8fdb\u5165\u540e\u53f0\u5728\u56de\u5230\u524d\u53f0 \u90a3\u4e48\u8fd9\u4e2a\u662f \u201c\u518d\u201d\u7684\u611f\u89c9\uff0c \u521d\u59cb\u5316\u8fdb\u5165 \u518d\u4e0a\u9762\u4ee5\u53ca\u6267\u884c\u4e86 onResume\n          } else if (state == AppLifecycleState.inactive) {\/\/ \u5904\u4e8e\u975e\u6fc0\u6d3b\u72b6\u6001\uff0c\u65e0\u6cd5\u54cd\u5e94\u7528\u6237\u8f93\u5165\n            onPause();\n          } else if (state == AppLifecycleState.paused) { \/\/ \u4e0d\u53ef\u89c1\u4e14\u65e0\u6cd5\u54cd\u5e94\u7528\u6237\u8f93\u5165\n            onStop();\n          } else if (state == AppLifecycleState.detached) {\n            onDestroy();\n          }\n        }\n      }\n\n      void onCreate() {}\n\n      void onDestroy() {\n        FTShowToastUtils.dismiss();\n      }\n\n      void onResume() {}\n\n      void onPause() {}\n\n      void onStop() {}\n\n      void onReStart() {}\n\n      @override\n      void didChangeDependencies() {\n        super.didChangeDependencies();\n        WidgetsBinding.instance.addObserver(this);\n        IIRouteObserver.instance.subscribe(this, ModalRoute.of(context));\n      }\n    }\n<\/code><\/pre>\n<h3>2. \u5bf9\u8bdd\u6846Dialog\u57fa\u7c7b<\/h3>\n<blockquote><p>\n  \u5c06\u95f4\u8ddd\u3001\u5706\u89d2\u7b49\u5c01\u88c5\n<\/p><\/blockquote>\n<pre><code class=\"language-dart line-numbers\">    import 'package:flutter\/material.dart';\n    import 'package:flutter_screenutil\/flutter_screenutil.dart';\n\n    abstract class BaseDialog extends StatefulWidget {\n      const BaseDialog({Key? key}) : super(key: key);\n\n      @override\n      BaseDialogState createState() =&gt; getState();\n\n      \/\/\/\u5b50\u7c7b\u5b9e\u73b0\n      BaseDialogState getState();\n    }\n\n    abstract class BaseDialogState&lt;T extends BaseDialog&gt; extends State&lt;T&gt; {\n      int milliseconds = 120;\n      double width = 0.8.sw;\n      double radis = 10;\n      double paddingHorizontal = 12.w;\n      double paddingVertical = 12.h;\n\n      @override\n      void initState() {\n        super.initState();\n        setDuration(milliseconds);\n        setDialogWidth(width);\n        setDialogRadis(radis);\n        setDialogPdHorizontal(paddingHorizontal);\n        setDialogPdVertical(paddingVertical);\n      }\n\n      @override\n      Widget build(BuildContext context) {\n        return Center(\n          child: AnimatedContainer(\n            width: 0.8.sw,\n            duration: Duration(milliseconds: milliseconds),\n            curve: Curves.easeInCubic,\n            child: Material(\n              borderRadius: BorderRadius.circular(10),\n              child: Container(\n                padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.h),\n                child: body(),\n              ),\n            ),\n          ),\n        );\n      }\n\n      \/\/ dialog\u4e3b\u9875\u9762\n      Widget body();\n\n      void setDuration(int milliseconds) {\n        this.milliseconds = milliseconds;\n      }\n\n      void setDialogWidth(double width) {\n        this.width = width;\n      }\n\n      void setDialogRadis(double radis) {\n        this.radis = radis;\n      }\n\n      void setDialogPdHorizontal(double paddingHorizontal) {\n        this.paddingHorizontal = paddingHorizontal;\n      }\n\n      void setDialogPdVertical(double paddingVertical) {\n        this.paddingVertical = paddingVertical;\n      }\n    }\n<\/code><\/pre>\n<h3>3. GetX\u63a7\u5236\u5668\u57fa\u7c7b\u5c01\u88c5<\/h3>\n<h4>3.1 Base<\/h4>\n<pre><code class=\"language-dart line-numbers\">    \/\/ \u7528\u4e8e\u8bbe\u7f6edio\u7684CancelToken\n    import 'dart:io';\n\n    import 'package:dio\/dio.dart';\n    import 'package:get_storage\/get_storage.dart';\n    import 'package:get\/get.dart';\n    import 'package:huadian\/net\/network_manager.dart';\n    import 'package:huadian\/net\/result.dart';\n    import 'package:huadian\/tools\/log_util.dart';\n\n    class BaseGetXController&lt;T&gt; extends GetxController {\n      fin\/\/ \u7528\u4e8e\u8bbe\u7f6edio\u7684CancelToken\nimport 'dart:io';\n\nimport 'package:dio\/dio.dart';\nimport 'package:flutter_easyloading\/flutter_easyloading.dart';\nimport 'package:get_storage\/get_storage.dart';\nimport 'package:get\/get.dart';\nimport 'package:huadian\/ext\/extends.dart';\nimport 'package:huadian\/net\/network_manager.dart';\nimport 'package:huadian\/net\/result.dart';\nimport 'package:huadian\/route\/route_config.dart';\nimport 'package:huadian\/tools\/alert_toast.dart';\nimport 'package:huadian\/tools\/config.dart';\nimport 'package:huadian\/util\/hjt_utils.dart';\n\nenum ViewErrorStateType{\n  ERROR_CLIENT,\n  ERROR_SERVICE,\n  ERROR_TIMEOUT,\n  ERROR_NETWORK,\n  ERROR_PARAMS,\n  DEFAULT\n}\n\nenum ViewState{\n  IDLE,\/\/  \u7a7a\u95f2\u4e2d\n  BUSY,\n  EMPTY,\n  ERROR,\n  \/\/  \u4ec5\u7528\u4e8e\u5c01\u88c5\u5185\u90e8\u6807\u8bb0 \u8c03\u7528\u8005\u65e0\u9700\u5173\u5fc3\u5e72\u561b\n  SUCCESS\n}\n\nabstract class BaseGetXController&lt;T&gt; extends GetxController {\n  var _errorStateType = ViewErrorStateType.DEFAULT.obs;\n  var _viewState = ViewState.IDLE.obs;\n\n  final sfs = GetStorage();\n\n  CancelToken _cancelToken = CancelToken();\n\n  T get to =&gt; Get.find();\n\n  CancelToken get cancelToken =&gt; _cancelToken;\n\n  @override\n  void onClose() {\n    super.onClose();\n    _cancelToken.cancel(\"\u5173\u95ed\u9875\u9762\uff0c\u53d6\u6d88\u6b63\u5728\u7684\u7f51\u7edc\u8bf7\u6c42\uff01\");\n  }\n\n  Future&lt;Result?&gt; get(String url, Map param,\n      {bool needToken = true,bool showLoading = true}) async {\n    _viewState.value = ViewState.BUSY;\n    Result? response = await HjtDio()\n        .get(url, param, token: needToken, cancelToken: _cancelToken,showLoading: showLoading);\n    _viewState.value = ViewState.IDLE;\n    return handleResponse(response);\n  }\n\n  Future&lt;Result?&gt; post&lt;T&gt;(String url, Map param,\n      {bool needToken = true,bool showLoading = true}) async {\n    _viewState.value = ViewState.BUSY;\n    Result? response = await HjtDio()\n        .post&lt;T&gt;(url, param, token: needToken, cancelToken: _cancelToken,showLoading: showLoading);\n    _viewState.value = ViewState.IDLE;\n    return handleResponse(response);\n  }\n\n  Result? handleResponse(Result? response){\n    Result? result;\n    response?.run((){\n      switch(response.code){\n        case TOKEN_EXPIRE:\n          loginExpire();\n          break;\n        case ERROR_TIMEOUT:\n          _errorStateType.value = ViewErrorStateType.ERROR_TIMEOUT;\n          _viewState.value = ViewState.ERROR;\n          break;\n        case ERROR_SERVICE:\n          _errorStateType.value = ViewErrorStateType.ERROR_SERVICE;\n          _viewState.value = ViewState.ERROR;\n          break;\n        case ERROR_CLIENT:\n          _errorStateType.value = ViewErrorStateType.ERROR_CLIENT;\n          _viewState.value = ViewState.ERROR;\n          break;\n        case ERROR_PARAMS:\n          _errorStateType.value = ViewErrorStateType.ERROR_PARAMS;\n          _viewState.value = ViewState.ERROR;\n          if(response.data is String &amp;&amp; !(response.data as String).isNullOrEmpty())\n            EasyLoading.showError(\"${response.data}\");\n          else\n            EasyLoading.showError(\"${response.msg}\");\n          break;\n        case ERROR_NETWORK:\n          _errorStateType.value = ViewErrorStateType.ERROR_NETWORK;\n          _viewState.value = ViewState.ERROR;\n          break;\n        case SUCCESS:\n        \/\/ \u9700\u8981 \u8c03\u7528\u8005 \u5bf9\u6570\u636e\u5224\u65ad \u4e3a\"\u7a7a\" \u8bbe\u7f6e\u72b6\u6001\n          _errorStateType.value = ViewErrorStateType.DEFAULT;\n          _viewState.value = ViewState.SUCCESS;\n          result = response;\n          break;\n      }\n    });\n    return result;\n  }\n\n  \/\/ \u4e0a\u4f20\u5355\u4e2a\u56fe\u7247\n  uploadSingleImage() async {\n    await HjtUtils.uploadSingleImage(cancelToken: _cancelToken);\n  }\n\n  \/\/ \u4e0a\u4f20\u591a\u4e2a\u591a\u62cd\n  uploadMultiImage() async {\n    await HjtUtils.uploadMultiImage(cancelToken: _cancelToken);\n  }\n\n  void loginExpire() {\n    AlertToast().showErrorAlertToast(\"\u767b\u5f55\u72b6\u6001\u5931\u6548\uff01\u8bf7\u91cd\u65b0\u767b\u5f55\u3002\");\n    Future.delayed(Duration(seconds: 1),() {\n      Get.toNamed(RouteConfig.login);\n    });\n  }\n\n\n  bool get isEmpty =&gt; _viewState.value == ViewState.EMPTY;\n  bool get isIdle =&gt; _viewState.value == ViewState.IDLE;\n  bool get isBusy =&gt; _viewState.value == ViewState.BUSY;\n  bool get isError =&gt; _viewState.value == ViewState.ERROR;\n\n  bool get isErrorClient =&gt; _errorStateType.value == ViewErrorStateType.ERROR_CLIENT;\n  bool get isErrorService =&gt; _errorStateType.value == ViewErrorStateType.ERROR_SERVICE;\n  bool get isErrorTimeout =&gt; _errorStateType.value == ViewErrorStateType.ERROR_TIMEOUT;\n  bool get isErrorNetwork =&gt; _errorStateType.value == ViewErrorStateType.ERROR_NETWORK;\n  bool get isErrorParams =&gt; _errorStateType.value == ViewErrorStateType.ERROR_PARAMS;\n  bool get isErrorDefault =&gt; _errorStateType.value == ViewErrorStateType.DEFAULT;\n\n  void setEmpty() {\n    _viewState.value = ViewState.EMPTY;\n  }\n\n  get viewState =&gt; _viewState.value;\n  get errorStateType =&gt; _errorStateType.value;\n\n}\n<\/code><\/pre>\n<h4>3.2 BasePageController\u7ee7\u627f\u4e0a\u8bc9\u7684\u7528\u4e8e\u5206\u9875\u4f7f\u7528<\/h4>\n<pre><code class=\"language-dart line-numbers\">\/\/ \u7528\u4e8e\u8bbe\u7f6edio\u7684CancelToken\nimport 'dart:io';\n\nimport 'package:dio\/dio.dart';\nimport 'package:flutter\/material.dart';\nimport 'package:flutter_easyrefresh\/easy_refresh.dart';\nimport 'package:get_storage\/get_storage.dart';\nimport 'package:get\/get.dart';\nimport 'package:huadian\/base\/base_getx_controller.dart';\nimport 'package:huadian\/net\/network_manager.dart';\nimport 'package:huadian\/net\/result.dart';\nimport 'package:huadian\/tools\/log_util.dart';\nimport 'package:huadian\/util\/hjt_utils.dart';\n\nabstract class BasePageGetXController&lt;T&gt; extends BaseGetXController&lt;T&gt; {\n  \/\/ \u591a Tab\u4f7f\u7528 \u4e00\u4e2aController\uff0c\u4fdd\u5b58\u6bcf\u4e2atab\u9875\u9762\u7684\u5f53\u524d\u5206\u9875 page\u53d8\u91cf\u3002\u5207\u6362tab\u91cd\u7f6e page\n\n  int _page = 1;\n\n  \/\/ \u9632\u6b62 \u9875\u7801\u53c2\u6570\u4e0d\u662f\u8fd9\u4e2a \u5916\u90e8\u8bbe\u7f6e  \u4e00\u822c\u90fd\u662f\u8fd9\u4e2a\u9664\u975e xxx\n  String _pageParams = \"page\";\n\n  String get pageParams =&gt; _pageParams;\n\n  set pageParams(String value) {\n    _pageParams = value;\n  }\n\n  int get page =&gt; _page;\n\n  set page(int value) {\n    _page = value;\n  }\n\n\n\n\n  \/\/ \u4e00\u4e9b\u63a7\u5236\u5668\u7b49\n  EasyRefreshController _easyRefreshController = EasyRefreshController();\n  ScrollController _scrollController = ScrollController();\n\n  EasyRefreshController get easyRefreshController =&gt; _easyRefreshController;\n  ScrollController get scrollController =&gt; _scrollController;\n\n\n\n  Future&lt;Result?&gt; get(String url, Map param,\n      {bool needToken = true,bool loadMore = false,bool showLoading = true}) async {\n    return await super.get(url, handleLoadMore(param,loadMore), needToken: needToken,showLoading: showLoading);\n  }\n\n  Future&lt;Result?&gt; post&lt;T&gt;(String url, Map param,\n      {bool needToken = true,bool loadMore = false,bool showLoading = true}) async {\n    return await super.post&lt;T&gt;(url, handleLoadMore(param,loadMore), needToken: needToken,showLoading: showLoading);\n  }\n\n  Map handleLoadMore(Map param, bool loadMore) {\n    if(loadMore){\n      page = page + 1;\n      param[pageParams] = page;\n    }else{\n      page = 1;\n      param[pageParams] = 1;\n    }\n    return param;\n  }\n\n\n\n\/\/ \u63a7\u5236\u5668\u7684\u72b6\u6001\n  void finishRefresh() {\n    resetLoadState();\n    easyRefreshController.finishRefresh();\n  }\n\n  void resetLoadState(){\n    easyRefreshController.resetLoadState();\n  }\n\n  void finishLoad(bool noMore){\n    easyRefreshController.finishLoad(noMore: noMore);\n  }\n}\n<\/code><\/pre>\n<h3>4. \u7f51\u7edc\u5c42<\/h3>\n<pre><code class=\"language-dart line-numbers\">import 'dart:convert';\nimport 'dart:typed_data';\nimport 'package:connectivity\/connectivity.dart';\nimport 'package:dio\/adapter.dart';\nimport 'package:dio\/dio.dart';\nimport 'package:flutter\/cupertino.dart';\nimport 'package:flutter_easyloading\/flutter_easyloading.dart';\nimport 'package:http_parser\/http_parser.dart';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:get_storage\/get_storage.dart';\nimport 'package:huadian\/ext\/env.dart';\nimport 'package:huadian\/net\/api.dart';\nimport 'package:huadian\/net\/result.dart';\nimport 'package:huadian\/tools\/alert_toast.dart';\nimport 'package:huadian\/tools\/config.dart';\nimport 'package:huadian\/ext\/extends.dart';\nimport 'package:huadian\/tools\/log_util.dart';\nimport 'package:huadian\/util\/pachage_version.dart';\nimport 'package:huadian\/util\/user_manager.dart';\n\nclass HjtDio {\nstatic final HjtDio _manager = HjtDio._init();\nstatic late Dio _dio;\n\nfinal box = GetStorage();\n\nHjtDio._init() {\n  BaseOptions options = BaseOptions(\n    baseUrl: GlobalConfig.saasUrl(),\n    connectTimeout: 1000 * 30,\n    \/\/ \u8fde\u63a5\u670d\u52a1\u5668\u8d85\u65f6\u65f6\u95f4\uff0c\u5355\u4f4d\u662f\u6beb\u79d2.\n    receiveTimeout: 1000 * 30,\n    \/\/ \u54cd\u5e94\u6d41\u4e0a\u524d\u540e\u4e24\u6b21\u63a5\u53d7\u5230\u6570\u636e\u7684\u95f4\u9694\uff0c\u5355\u4f4d\u4e3a\u6beb\u79d2, \u8fd9\u5e76\u4e0d\u662f\u63a5\u6536\u6570\u636e\u7684\u603b\u65f6\u9650.\n    responseType: ResponseType.json,\n    contentType: \"application\/json\",\n  );\n  PackageVersionInfo.instance!.init();\n  _dio = Dio(options);\n\n  \/\/ \u6dfb\u52a0\u62e6\u622a\u5668\n  \/\/ if (GlobalConfig.env != Env.Formal) {\n  _dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {\n    print(\"\\n================== \u8bf7\u6c42\u6570\u636e ==========================\");\n    print(\"url = ${options.uri.toString()}\");\n    print(\"headers = ${options.headers}\");\n    LogUtil.d(\"data = ${options.data}\");\n    LogUtil.d(\"params = ${options.queryParameters}\");\n    return handler.next(options);\n  }, onResponse: (response, handler) {\n    print(\"\\n================== \u54cd\u5e94\u6570\u636e ==========================\");\n    print(\"code = ${response.statusCode}\");\n    LogUtil.d(response);\n    print(\"\\n\");\n    return handler.next(response);\n  }));\n\n  \/\/ \u8fd9\u91cc\u52a0\u4e86 \u4e0b\u9762\u5c31\u6355\u83b7\u4e0d\u5230\u4e0d\u80fd\u5904\u7406\u4e86\n  \/*\n  , onError: (error, handler) {\n    print(\"\\n================== \u9519\u8bef\u54cd\u5e94\u6570\u636e ======================\");\n    print(\"type = ${error.type}\");\n    print(\"message = ${error.message}\");\n    print(\"stackTrace = ${error.stackTrace}\");\n    print(\"\\n\");\n  }\n   *\/\n  \/\/ }\n\n  if (GlobalConfig.isProxyChecked) {\n    (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =\n        (client) {\n      client.badCertificateCallback =\n          (X509Certificate cert, String host, int port) {\n        return GlobalConfig.isProxyChecked;\n      };\n      client.findProxy = (url) {\n        return 'PROXY ${GlobalConfig.proxy}';\n      };\n      return client;\n    };\n  }\n}\n\nfactory HjtDio() {\n  return _manager;\n}\n\nFuture&lt;Result?&gt; get&lt;T&gt;(\n  url,\n  param, {\n  bool token = true,\n  bool showLoading = true,\n  CancelToken? cancelToken,\n  String? contentType\n}) async {\n  return await request&lt;T&gt;(url,\n      queryParameters: param, method: Method.get, token: token,cancelToken: cancelToken,contentType: contentType);\n}\n\nFuture&lt;Result?&gt; post&lt;T&gt;(\n  url,\n  param, {\n  bool token = true,\n  bool showLoading = true,\n  CancelToken? cancelToken,\n  String? contentType\n}) async {\n  return await request&lt;T&gt;(url,\n      data: param,\n      method: Method.post,\n      token: token,\n      showLoading: showLoading,\n      cancelToken: cancelToken,contentType: contentType);\n}\n\nFuture&lt;Result?&gt; request&lt;T&gt;(String path,\n    {String method = 'GET',\n    String? contentType = \"application\/x-www-form-urlencoded;charset=utf-8\",\n    \/\/ String contentType = \"application\/json; charset=UTF-8\",\n    bool token = true,\n    bool showLoading = true,\n    dynamic data,\n    CancelToken? cancelToken,\n    Map&lt;String, dynamic&gt;? queryParameters,\n    Options? options}) async {\n  var connectivityResult = await (new Connectivity().checkConnectivity());\n  \/\/ \u65e0\u7f51\n  if (connectivityResult == ConnectivityResult.none) {\n    return Result(ERROR_NETWORK,\"\u65e0\u7f51\u7edc\u8fde\u63a5\uff01\u8bf7\u68c0\u67e5\u7f51\u7edc\u8bbe\u7f6e\u3002\",null);\n  }\n\n  Response response;\n\n  if (token) {\n    String? token = UserManager().getToken();\n    print(\"token = $token\");\n    if (token == null) {\n      return Result(TOKEN_EXPIRE,\"\u767b\u5f55\u72b6\u6001\u5931\u6548\uff01\u8bf7\u91cd\u65b0\u767b\u5f55\u3002\",null);\n    }\n    _dio.options.headers.addAll({'token': token});\n  }\n\n  _dio.options.contentType = contentType;\n  _dio.options.method = method;\n\n  \/\/ \u9ed8\u8ba4 \u7f51\u7edc\u8bf7\u6c42\u81ea\u52a8\u5c55\u793a\u52a0\u8f7d\u4e2d\n  if (showLoading) EasyLoading.show();\n\n  try {\n    response = await _dio.request(path,\n        queryParameters: queryParameters,\n        cancelToken: cancelToken,\n        data: data);\n\n    EasyLoading.dismiss();\n\n    \/\/ \u4e0d\u7528\u5224\u65ad\u4e5f\u53ef \u5fc5\u4e3a200\n    if (response.statusCode == 200) { \/\/ \u670d\u52a1\u5668\u6b63\u5e38\u7ed9 \u7ed3\u679c\n      try {\n        Result result = Result.fromJson(response.data);\n        \/\/ \u53ef\u4ee5\u5728\u8fd9 \u5bf9\u4e0d\u540c\u7684code\u7801 \u8fdb\u884c\u5904\u7406  \u5982\uff1a\u767b\u5f55\u5931\u6548\u7b49\n        if (result.code == TOKEN_EXPIRE){\n          result.code = TOKEN_EXPIRE;\n        } else if(result.code != SUCCESS){\n          result.code = ERROR_PARAMS;\n        } \/\/ \u5176\u4ed6\u989d\u5916\u7684code\n        return result;\n      } catch (e,s) {\n        return Result(ERROR_CLIENT,\"\u5ba2\u6237\u7aef\u9519\u8bef\uff01\",null);\n      }\n    }\n    return Result(ERROR_CLIENT,\"\u5ba2\u6237\u7aef\u9519\u8bef\uff01\",null);\n  } catch (error, s) {\n    var result = Result(ERROR_CLIENT,\"\u672a\u77e5\u9519\u8bef\uff01\",null);\n    if (error is DioError) {\n\n      debugPrint(\"\\n================== \u9519\u8bef\u54cd\u5e94\u6570\u636e ======================\");\n      debugPrint(\"type = ${error.type}\");\n      debugPrint(\"message = ${error.message}\");\n      debugPrint(\"stackTrace = ${error.stackTrace}\");\n      debugPrint(\"\\n\");\n\n      switch (error.type) {\n        case DioErrorType.connectTimeout:\n        case DioErrorType.sendTimeout:\n        case DioErrorType.receiveTimeout:\n          result =  Result(ERROR_TIMEOUT,\"\u7f51\u7edc\u8bf7\u6c42\u8d85\u65f6\u9519\u8bef\uff01\",null);\n          break;\n        case DioErrorType.response: \/\/ \u670d\u52a1\u5668\u975e200\u8fd4\u56de\n        \/\/ \u975e\u6b63\u5e38\u8bf7\u6c42\u670d\u52a1\u5668200\n          if (showLoading)\n            AlertToast().showErrorAlertToast(error.message);\n          result = Result(ERROR_SERVICE,\"\u670d\u52a1\u5668\u9519\u8bef\uff01\",null);\n          break;\n        case DioErrorType.cancel:\n          result = Result(ERROR_CLIENT,\"\u7f51\u7edc\u8bf7\u6c42\u53d6\u6d88\uff01\",null);\n          break;\n        case DioErrorType.other:\n          if (showLoading)\n            AlertToast().showErrorAlertToast(error.message);\n          break;\n      }\n    }\n    return result;\n  }\n}\n\n\/\/ \u4e0d\u53ef\u7528\nFuture&lt;Result?&gt; uploadImage({required String? path,CancelToken? cancelToken}) async {\n  if(path.isNullOrEmpty()){\n    return Result(ERROR_CLIENT,\"\u56fe\u7247\u8def\u5f84\u4e3a\u7a7a\uff01\",null);\n  }\n  var name = path!.substring(path.lastIndexOf(\"\/\") + 1, path.length);\n  FormData formData = FormData.fromMap({\n    \"color\": \"#e3e3e3\",\n    \"size\": 16,\n    \"iswatermark\": 0,\n    \/\/ \u6ca1\u6709\u6c34\u5370\n    \"file\": MultipartFile.fromFile(path, filename: name),\n  });\n  \/\/ return request(Api.API_UPLOAD_IMAGE,data: formData,contentType: \"application\/octet-stream\", method: Method.post,);\n  return request(Api.API_UPLOAD_IMAGE,data: formData,contentType: \"multipart\/form-data\", method: Method.post,);\n}\n\nFuture&lt;Result?&gt; uploadMemoryImage({required Uint8List uint8list,CancelToken? cancelToken,bool showLoading = true}) async {\n  FormData formData = FormData.fromMap({\n    \"color\": \"#e3e3e3\",\n    \"size\": 16,\n    \"iswatermark\": 0,\n    \"file\": MultipartFile.fromBytes(\n      uint8list,\n      \/\/ \u6587\u4ef6\u540d\n      filename: 'gallery.jpg',\n      \/\/ \u6587\u4ef6\u7c7b\u578b\n      contentType: MediaType(\"image\", \"jpg\"),\n    )\n  });\n  \/\/ return request(Api.API_UPLOAD_IMAGE,data: formData,contentType: \"application\/octet-stream\", method: Method.post,);\n  return request(Api.API_UPLOAD_IMAGE,data: formData,contentType: \"multipart\/form-data\", method: Method.post,showLoading: showLoading);\n}\n\nint failUploadNum = 0;\n\/\/ \u591a\u5f20\u5206\u5f00\u4e00\u4e2a\u4e00\u4e2a\u53d1  \u6548\u679c\u4e0a\u5b9e\u73b0 \u591a\u56fe\u4e0a\u4f20\nFuture&lt;Result?&gt; uploadMemoryImageByForge({required List&lt;Uint8List&gt; fileList,CancelToken? cancelToken}) async {\n  failUploadNum = 0;\n  int len = fileList.length;\n  for (int i = 0; i &lt; len; i++) {\n    EasyLoading.show(status: \"\u4e0a\u4f20\u4e2d...($i\/$len) \\n \u5931\u8d25\u4e2a\u6570: $failUploadNum\");\n    try{ \/\/ \u67d0\u4e00\u5f20\u51fa\u9519 \u4e0d\u5f71\u54cd\u5176\u4ed6\u7684\n      Result? result = await uploadMemoryImage(uint8list: fileList[i],cancelToken: cancelToken,showLoading: false);\n      if(result?.code!=200){\n        failUploadNum = failUploadNum + 1;\n      }\n    }catch(e){}\n  }\n  EasyLoading.showToast(\"\u4e0a\u4f20\u6210\u529f ${len -failUploadNum}\u4e2a \u5931\u8d25 $failUploadNum\u4e2a\",duration: Duration(milliseconds: 1500));\n}\n\n\/\/ \u540e\u7aef\u4e0d\u652f\u6301 \u591a\u5f20\u4e00\u8d77\u4e0a\u4f20\nFuture&lt;Result?&gt; uploadMemoryImageList({required List&lt;Uint8List&gt; fileList,CancelToken? cancelToken}) async {\n  List&lt;MultipartFile&gt; files = [];\n  for (int i = 0; i &lt; fileList.length; i++) {\n    files.add(MultipartFile.fromBytes(\n      fileList[i],\n      \/\/ \u6587\u4ef6\u540d\n      filename: 'gallery_$i.jpg',\n      \/\/ \u6587\u4ef6\u7c7b\u578b\n      contentType: MediaType(\"image\", \"jpg\"),\n    ));\n  }\n  FormData formData = FormData.fromMap({\n    \"color\": \"#e3e3e3\",\n    \"size\": 16,\n    \"iswatermark\": 0,\n    \"file\": files\n  });\n  \/\/ return request(Api.API_UPLOAD_IMAGE,data: formData,contentType: \"application\/octet-stream\", method: Method.post,);\n  return request(Api.API_UPLOAD_IMAGE,data: formData,contentType: \"multipart\/form-data\", method: Method.post,);\n}\n\n\/\/ \/\/ \u4e0b\u8f7d\u56fe\u7247\n\/\/ void downLoadImageSave2Gallery(String url,{CancelToken? cancelToken}) async {\n\/\/   EasyLoading.show(status: \"\u4e0b\u8f7d\u4e2d...\");\n\/\/   try {\n\/\/     \/\/ https:\/\/sv.huaji.com\/huaji_saas_220107134805_2729.jpeg\n\/\/     var response = await Dio().get(url,\n\/\/         options: Options(responseType: ResponseType.bytes));\n\/\/     final result = await ImageGallerySaver.saveImage(\n\/\/         Uint8List.fromList(response.data),\n\/\/         quality: 60,\n\/\/         name: url.substring(url.lastIndexOf(\"\/\")));\n\/\/     EasyLoading.showSuccess(\"\u5df2\u4fdd\u5b58\u5230\u7cfb\u7edf\u76f8\u518c\uff01\");\n\/\/     print(result);\n\/\/   } on DioError catch (e) {\n\/\/     EasyLoading.showError(\"\u4fdd\u5b58\u5931\u8d25: $e\");\n\/\/     print('downloadFile error---------$e');\n\/\/   }\n\/\/ }\n\n\/\/ \u4e0b\u8f7d\u8d44\u6e90\n\/\/ void downLoadResource2System(String url,{String? savePath}) async {\n\/\/   try {\n\/\/     String? path;\n\/\/     if(savePath!=null){\n\/\/       path = savePath + url.substring(url.lastIndexOf(\"\/\"));\n\/\/     }else{\n\/\/       var appDir = await getTemporaryDirectory();\n\/\/       path = appDir.path + url.substring(url.lastIndexOf(\"\/\"));\n\/\/     }\n\/\/     await Dio().download(url, savePath,onReceiveProgress: (int count, int total){\n\/\/       EasyLoading.showProgress(count\/total,status: \"\u4e0b\u8f7d\u4e2d...\");\n\/\/     });\n\/\/     final result = await ImageGallerySaver.saveFile(path);\n\/\/     EasyLoading.showSuccess(\"\u5df2\u4fdd\u5b58\u5230\u624b\u673a\uff01\");\n\/\/     print(result);\n\/\/   }catch(e){\n\/\/     EasyLoading.showError(\"\u4e0b\u8f7d\u5931\u8d25: $e\");\n\/\/     print('downloadFile error---------$e');\n\/\/   }\n\/\/ }\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>1. \u9875\u9762\u57fa\u7c7b \u652f\u6301\u7f51\u7edc\u65ad\u5f00\u540e\u91cd\u8bd5\u3001\u4effAndroid\u751f\u547d\u5468\u671f import &#8216;dart:async&#8217;; imp [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[4],"class_list":["post-87","post","type-post","status-publish","format-standard","hentry","category-8","tag-flutter"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Flutter-\u57fa\u7c7b\u5c01\u88c5 - IIchen<\/title>\n<meta name=\"description\" content=\"\u5173\u4e8eFlutter\u57fa\u7c7b\u7684\u5c01\u88c5\uff0c\u5305\u542b\u9875\u9762\u3001\u5bf9\u8bdd\u6846\u4ee5\u53cagetx\u63a7\u5236\u5668\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/iichen.cn\/?p=87\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Flutter-\u57fa\u7c7b\u5c01\u88c5 - IIchen\" \/>\n<meta property=\"og:description\" content=\"\u5173\u4e8eFlutter\u57fa\u7c7b\u7684\u5c01\u88c5\uff0c\u5305\u542b\u9875\u9762\u3001\u5bf9\u8bdd\u6846\u4ee5\u53cagetx\u63a7\u5236\u5668\" \/>\n<meta property=\"og:url\" content=\"https:\/\/iichen.cn\/?p=87\" \/>\n<meta property=\"og:site_name\" content=\"IIchen\" \/>\n<meta property=\"article:published_time\" content=\"2022-02-07T05:34:41+00:00\" \/>\n<meta name=\"author\" content=\"iichen\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"iichen\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/iichen.cn\/?p=87#article\",\"isPartOf\":{\"@id\":\"https:\/\/iichen.cn\/?p=87\"},\"author\":{\"name\":\"iichen\",\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c\"},\"headline\":\"Flutter-\u57fa\u7c7b\u5c01\u88c5\",\"datePublished\":\"2022-02-07T05:34:41+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/iichen.cn\/?p=87\"},\"wordCount\":6,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c\"},\"keywords\":[\"Flutter\"],\"articleSection\":[\"\u7b14\u8bb0\"],\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/iichen.cn\/?p=87#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/iichen.cn\/?p=87\",\"url\":\"https:\/\/iichen.cn\/?p=87\",\"name\":\"Flutter-\u57fa\u7c7b\u5c01\u88c5 - IIchen\",\"isPartOf\":{\"@id\":\"https:\/\/iichen.cn\/#website\"},\"datePublished\":\"2022-02-07T05:34:41+00:00\",\"description\":\"\u5173\u4e8eFlutter\u57fa\u7c7b\u7684\u5c01\u88c5\uff0c\u5305\u542b\u9875\u9762\u3001\u5bf9\u8bdd\u6846\u4ee5\u53cagetx\u63a7\u5236\u5668\",\"breadcrumb\":{\"@id\":\"https:\/\/iichen.cn\/?p=87#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/iichen.cn\/?p=87\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/iichen.cn\/?p=87#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/iichen.cn\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Flutter-\u57fa\u7c7b\u5c01\u88c5\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/iichen.cn\/#website\",\"url\":\"https:\/\/iichen.cn\/\",\"name\":\"IIchen\",\"description\":\"Just do it!\",\"publisher\":{\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/iichen.cn\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"zh-Hans\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c\",\"name\":\"iichen\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/avatar.jpg\",\"contentUrl\":\"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/avatar.jpg\",\"width\":940,\"height\":940,\"caption\":\"iichen\"},\"logo\":{\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/image\/\"},\"sameAs\":[\"https:\/\/www.iichen.cn\"],\"url\":\"https:\/\/iichen.cn\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Flutter-\u57fa\u7c7b\u5c01\u88c5 - IIchen","description":"\u5173\u4e8eFlutter\u57fa\u7c7b\u7684\u5c01\u88c5\uff0c\u5305\u542b\u9875\u9762\u3001\u5bf9\u8bdd\u6846\u4ee5\u53cagetx\u63a7\u5236\u5668","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/iichen.cn\/?p=87","og_locale":"zh_CN","og_type":"article","og_title":"Flutter-\u57fa\u7c7b\u5c01\u88c5 - IIchen","og_description":"\u5173\u4e8eFlutter\u57fa\u7c7b\u7684\u5c01\u88c5\uff0c\u5305\u542b\u9875\u9762\u3001\u5bf9\u8bdd\u6846\u4ee5\u53cagetx\u63a7\u5236\u5668","og_url":"https:\/\/iichen.cn\/?p=87","og_site_name":"IIchen","article_published_time":"2022-02-07T05:34:41+00:00","author":"iichen","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"iichen","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"11 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/iichen.cn\/?p=87#article","isPartOf":{"@id":"https:\/\/iichen.cn\/?p=87"},"author":{"name":"iichen","@id":"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c"},"headline":"Flutter-\u57fa\u7c7b\u5c01\u88c5","datePublished":"2022-02-07T05:34:41+00:00","mainEntityOfPage":{"@id":"https:\/\/iichen.cn\/?p=87"},"wordCount":6,"commentCount":0,"publisher":{"@id":"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c"},"keywords":["Flutter"],"articleSection":["\u7b14\u8bb0"],"inLanguage":"zh-Hans","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/iichen.cn\/?p=87#respond"]}]},{"@type":"WebPage","@id":"https:\/\/iichen.cn\/?p=87","url":"https:\/\/iichen.cn\/?p=87","name":"Flutter-\u57fa\u7c7b\u5c01\u88c5 - IIchen","isPartOf":{"@id":"https:\/\/iichen.cn\/#website"},"datePublished":"2022-02-07T05:34:41+00:00","description":"\u5173\u4e8eFlutter\u57fa\u7c7b\u7684\u5c01\u88c5\uff0c\u5305\u542b\u9875\u9762\u3001\u5bf9\u8bdd\u6846\u4ee5\u53cagetx\u63a7\u5236\u5668","breadcrumb":{"@id":"https:\/\/iichen.cn\/?p=87#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/iichen.cn\/?p=87"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/iichen.cn\/?p=87#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/iichen.cn\/"},{"@type":"ListItem","position":2,"name":"Flutter-\u57fa\u7c7b\u5c01\u88c5"}]},{"@type":"WebSite","@id":"https:\/\/iichen.cn\/#website","url":"https:\/\/iichen.cn\/","name":"IIchen","description":"Just do it!","publisher":{"@id":"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/iichen.cn\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"zh-Hans"},{"@type":["Person","Organization"],"@id":"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c","name":"iichen","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/iichen.cn\/#\/schema\/person\/image\/","url":"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/avatar.jpg","contentUrl":"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/avatar.jpg","width":940,"height":940,"caption":"iichen"},"logo":{"@id":"https:\/\/iichen.cn\/#\/schema\/person\/image\/"},"sameAs":["https:\/\/www.iichen.cn"],"url":"https:\/\/iichen.cn\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/posts\/87","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/iichen.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=87"}],"version-history":[{"count":0,"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/posts\/87\/revisions"}],"wp:attachment":[{"href":"https:\/\/iichen.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=87"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/iichen.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=87"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/iichen.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=87"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}