Giter Club home page Giter Club logo

vnote_flutter's Introduction

vnote

用 Flutter 写的 VNote 移动端!

介绍

眨眼一年过去了,这几天工作上解决了一些问题,突然想起,去年这个问题,在这里也出现过,于是,更新一下,让项目跑起来,然后修复之。

为了能够正常下载图片

dio 要修改form_data.dart, 才能成功上传, 可以通过点击如下图来找到form_data.dart

老版本修改如下:

import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'multipart_file.dart';
import 'utils.dart';

/// A class to create readable "multipart/form-data" streams.
/// It can be used to submit forms and file uploads to http server.
class FormData {
  static const String _BOUNDARY_PRE_TAG = '--dio-boundary-';
  static const _BOUNDARY_LENGTH = _BOUNDARY_PRE_TAG.length + 10;

  /// The boundary of FormData, it consists of a constant prefix and a random
  /// postfix to assure the the boundary unpredictable and unique, each FormData
  /// instance will be different. And you can custom it by yourself.
  String _boundary;

  String get boundary => _boundary;

  final _newlineRegExp = RegExp(r'\r\n|\r|\n');

  /// The form fields to send for this request.
  final fields = <MapEntry<String, String>>[];

  /// The [files].
  final files = <MapEntry<String, MultipartFile>>[];

  /// Whether [finalize] has been called.
  bool get isFinalized => _isFinalized;
  bool _isFinalized = false;

  FormData() {
    _init();
  }

  /// Create FormData instance with a Map.
  FormData.fromMap(Map<String, dynamic> map) {
    _init();
    encodeMap(
      map,
      (key, value) {
        if (value == null) return null;
        if (value is MultipartFile) {
          files.add(MapEntry(key, value));
        } else {
          fields.add(MapEntry(key, value.toString()));
        }
        return null;
      },
      encode: false,
    );
  }

  void _init() {
    // Assure the boundary unpredictable and unique
    var random = Random();
    _boundary = _BOUNDARY_PRE_TAG +
        random.nextInt(4294967296).toString().padLeft(10, '0');
  }

  /// Returns the header string for a field. The return value is guaranteed to
  /// contain only ASCII characters.
  String _headerForField(String name, String value) {
    var header =
        'content-disposition: form-data; name="${_browserEncode(name)}"';
    if (!isPlainAscii(value)) {
      header = '$header\r\n'
          'content-type: text/plain; charset=utf-8\r\n'
          'content-transfer-encoding: binary';
    }
    return '$header\r\n\r\n';
  }

  /// Returns the header string for a file. The return value is guaranteed to
  /// contain only ASCII characters.
  String _headerForFile(MapEntry<String, MultipartFile> entry) {
    var file = entry.value;
    var header =
        'content-disposition: form-data; name="${_browserEncode(entry.key)}"';
    if (file.filename != null) {
      header = '$header; filename="${_browserEncode(file.filename)}"';
    }
    header = '$header\r\n'
        'content-type: ${file.contentType}';
    return '$header\r\n\r\n';
  }

  /// Encode [value] in the same way browsers do.
  String _browserEncode(String value) {
    // http://tools.ietf.org/html/rfc2388 mandates some complex encodings for
    // field names and file names, but in practice user agents seem not to
    // follow this at all. Instead, they URL-encode `\r`, `\n`, and `\r\n` as
    // `\r\n`; URL-encode `"`; and do nothing else (even for `%` or non-ASCII
    // characters). We follow their behavior.
    return value.replaceAll(_newlineRegExp, '%0D%0A').replaceAll('"', '%22');
  }

  /// The total length of the request body, in bytes. This is calculated from
  /// [fields] and [files] and cannot be set manually.
  int get length {
    var length = 0;
    for (var file in files) {
      length +=
          file.value.length;
    }

    return length;
  }

  Stream<List<int>> finalize() {
    if (isFinalized) {
      throw StateError("Can't finalize a finalized MultipartFile.");
    }
    _isFinalized = true;
    var controller = StreamController<List<int>>(sync: false);
    void writeAscii(String string) {
      controller.add(utf8.encode(string));
    }

    void writeUtf8(String string) => controller.add(utf8.encode(string));
    void writeLine() => controller.add([13, 10]); // \r\n

//    fields.forEach((entry) {
//      writeAscii('--$boundary\r\n');
//      writeAscii(_headerForField(entry.key, entry.value));
//      writeUtf8(entry.value);
//      writeLine();
//    });

    Future.forEach(files, (file) {
      //writeAscii('--$boundary\r\n');
      //writeAscii(_headerForFile(file));
      return writeStreamToSink(file.value.finalize(), controller)
          ;
    }).then((_) {
      //writeAscii('--$boundary--\r\n');
      controller.close();
    });
    return controller.stream;
  }

  ///Transform the entire FormData contents as a list of bytes asynchronously.
  Future<List<int>> readAsBytes() {
    return finalize().reduce((a, b) => [...a, ...b]);
  }
}

新版本改成如下:

import 'dart:async';
import 'dart:convert';
import 'dart:math';

import 'multipart_file.dart';
import 'options.dart';
import 'utils.dart';

/// A class to create readable "multipart/form-data" streams.
/// It can be used to submit forms and file uploads to http server.
class FormData {
  static const String _BOUNDARY_PRE_TAG = '--dio-boundary-';
  static const _BOUNDARY_LENGTH = _BOUNDARY_PRE_TAG.length + 10;

  late String _boundary;

  /// The boundary of FormData, it consists of a constant prefix and a random
  /// postfix to assure the the boundary unpredictable and unique, each FormData
  /// instance will be different.
  String get boundary => _boundary;

  final _newlineRegExp = RegExp(r'\r\n|\r|\n');

  /// The form fields to send for this request.
  final fields = <MapEntry<String, String>>[];

  /// The [files].
  final files = <MapEntry<String, MultipartFile>>[];

  /// Whether [finalize] has been called.
  bool get isFinalized => _isFinalized;
  bool _isFinalized = false;

  FormData() {
    _init();
  }

  /// Create FormData instance with a Map.
  FormData.fromMap(
    Map<String, dynamic> map, [
    ListFormat collectionFormat = ListFormat.multi,
  ]) {
    _init();
    encodeMap(
      map,
      (key, value) {
        if (value == null) return null;
        if (value is MultipartFile) {
          files.add(MapEntry(key, value));
        } else {
          fields.add(MapEntry(key, value.toString()));
        }
        return null;
      },
      listFormat: collectionFormat,
      encode: false,
    );
  }

  void _init() {
    // Assure the boundary unpredictable and unique
    var random = Random();
    _boundary = _BOUNDARY_PRE_TAG +
        random.nextInt(4294967296).toString().padLeft(10, '0');
  }

  /// Returns the header string for a field. The return value is guaranteed to
  /// contain only ASCII characters.
  String _headerForField(String name, String value) {
    var header =
        'content-disposition: form-data; name="${_browserEncode(name)}"';
    if (!isPlainAscii(value)) {
      header = '$header\r\n'
          'content-type: text/plain; charset=utf-8\r\n'
          'content-transfer-encoding: binary';
    }
    return '$header\r\n\r\n';
  }

  /// Returns the header string for a file. The return value is guaranteed to
  /// contain only ASCII characters.
  String _headerForFile(MapEntry<String, MultipartFile> entry) {
    var file = entry.value;
    var header =
        'content-disposition: form-data; name="${_browserEncode(entry.key)}"';
    if (file.filename != null) {
      header = '$header; filename="${_browserEncode(file.filename)}"';
    }
    header = '$header\r\n'
        'content-type: ${file.contentType}';
    return '$header\r\n\r\n';
  }

  /// Encode [value] in the same way browsers do.
  String? _browserEncode(String? value) {
    // http://tools.ietf.org/html/rfc2388 mandates some complex encodings for
    // field names and file names, but in practice user agents seem not to
    // follow this at all. Instead, they URL-encode `\r`, `\n`, and `\r\n` as
    // `\r\n`; URL-encode `"`; and do nothing else (even for `%` or non-ASCII
    // characters). We follow their behavior.
    if (value == null) {
      return null;
    }
    return value.replaceAll(_newlineRegExp, '%0D%0A').replaceAll('"', '%22');
  }

  /// The total length of the request body, in bytes. This is calculated from
  /// [fields] and [files] and cannot be set manually.
  int get length {
    var length = 0;
    // fields.forEach((entry) {
    //   length += '--'.length +
    //       _BOUNDARY_LENGTH +
    //       '\r\n'.length +
    //       utf8.encode(_headerForField(entry.key, entry.value)).length +
    //       utf8.encode(entry.value).length +
    //       '\r\n'.length;
    // });

    for (var file in files) {
      // length += '--'.length +
      //     _BOUNDARY_LENGTH +
      //     '\r\n'.length +
      //     utf8.encode(_headerForFile(file)).length +
      //     file.value.length +
      //     '\r\n'.length;
      length += file.value.length;
    }

    // return length + '--'.length + _BOUNDARY_LENGTH + '--\r\n'.length;
    return length;
  }

  Stream<List<int>> finalize() {
    if (isFinalized) {
      throw StateError("Can't finalize a finalized MultipartFile.");
    }
    _isFinalized = true;
    var controller = StreamController<List<int>>(sync: false);
    void writeAscii(String string) {
      controller.add(utf8.encode(string));
    }

    void writeUtf8(String string) => controller.add(utf8.encode(string));
    void writeLine() => controller.add([13, 10]); // \r\n

    // fields.forEach((entry) {
    //   writeAscii('--$boundary\r\n');
    //   writeAscii(_headerForField(entry.key, entry.value));
    //   writeUtf8(entry.value);
    //   writeLine();
    // });

    Future.forEach<MapEntry<String, MultipartFile>>(files, (file) {
      // writeAscii('--$boundary\r\n');
      // writeAscii(_headerForFile(file));
      return writeStreamToSink(file.value.finalize(), controller)
          ;//.then((_) => writeLine());
    }).then((_) {
      writeAscii('--$boundary--\r\n');
      controller.close();
    });
    return controller.stream;
  }

  ///Transform the entire FormData contents as a list of bytes asynchronously.
  Future<List<int>> readAsBytes() {
    return Future(() => finalize().reduce((a, b) => [...a, ...b]));
  }
}

build 报错了

运行flutter 构建时,长时间卡在Running Gradle task 'assembleDebug'...

flutter build apk -v

build 了很久没有反应, 最后报错大概如下:

[+104793 ms] FAILURE: Build failed with an exception.
[   +3 ms] * What went wrong:
[        ] Could not determine the dependencies of task ':app:lintVitalRelease'.
[        ] > Could not resolve all artifacts for configuration ':app:debugCompileClasspath'.
[   +1 ms]    > Could not download armeabi_v7a_debug.jar (io.flutter:armeabi_v7a_debug:1.0.0-540786dd51f112885a89792d678296b95e6622e5)
[        ]       > Could not get resource 'https://storage.googleapis.com/download.flutter.io/io/flutter/armeabi_v7a_debug/1.0.0-540786dd51f112885a89792d678296b95e6622e5/armeabi_v7a_debug-1.0.0-540786dd51f112885a89792d678296b95e6622e5.jar'.
[        ]          > Could not GET 'https://storage.googleapis.com/download.flutter.io/io/flutter/armeabi_v7a_debug/1.0.0-540786dd51f112885a89792d678296b95e6622e5/armeabi_v7a_debug-1.0.0-540786dd51f112885a89792d678296b95e6622e5.jar'.
[        ]             > Connect to storage.googleapis.com:443 [storage.googleapis.com/34.64.4.16] failed: Read timed out
[        ]    > Could not download arm64_v8a_debug.jar (io.flutter:arm64_v8a_debug:1.0.0-540786dd51f112885a89792d678296b95e6622e5)
[   +1 ms]       > Could not get resource 'https://storage.googleapis.com/download.flutter.io/io/flutter/arm64_v8a_debug/1.0.0-540786dd51f112885a89792d678296b95e6622e5/arm64_v8a_debug-1.0.0-540786dd51f112885a89792d678296b95e6622e5.jar'.
[        ]          > Could not GET 'https://storage.googleapis.com/download.flutter.io/io/flutter/arm64_v8a_debug/1.0.0-540786dd51f112885a89792d678296b95e6622e5/arm64_v8a_debug-1.0.0-540786dd51f112885a89792d678296b95e6622e5.jar'.
[        ]             > Connect to storage.googleapis.com:443 [storage.googleapis.com/34.64.4.16] failed: Read timed out
[        ] * Try:
[        ] Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
[        ] * Get more help at https://help.gradle.org
[        ] BUILD FAILED in 1m 51s

方法 1

运行时会卡在Running 'gradle assembleDebug, 因为Gradle的Maven仓库在国外, 可以使用阿里云的镜像地址

修改android下的build.gradle如下:

maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }

修改Flutter SDK包下的flutter.gradle文件, 如我的目录是: /Users/hua/flutter/packages/flutter_tools/gradle/flutter.gradle

repositories{
    google()
    gcenter()
}

改成

maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }

方法2

使用方法 1 还是解决不了, 请继续往下看.

解决地址: https://stackoverflow.com/questions/5991194/gradle-proxy-configuration

添加如下到gradle.properties, 其中1087是我的 v2ray http 监听端口. Android Studio 不用设置代理, 设置了也没用...

systemProp.http.proxyHost=127.0.0.1
systemProp.http.proxyPort=1087
systemProp.https.proxyHost=127.0.0.1
systemProp.https.proxyPort=1087

Android SDK 30的问题

在预览markdown的时候,会提示"ERR_ACCESS_DENIED"

flutter/flutter#71822

打包

ios

https://blog.csdn.net/A807296772/article/details/106493492

flutter build ios --release

Android

https://www.jianshu.com/p/0f48ec10fd32

flutter build apk

apk在build/app/outputs/flutter-apk/app-release.apk

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.