1 Star 0 Fork 0

shaodong_wu / LJ_NetDisk

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

浪尖网盘


Api 文档:https://docs.apipost.cn/preview/9935159a2f4504e2/7a3575dd42dba43f

项目说明 💻

  • 项目名称:浪尖网盘
  • 项目简介:基于 Flutter 跨平台框架开发的网盘类移动端APP,实现用户文件的上传预览等基本功能
  • 技术栈:Flutter、Dart、Dio、Provider、ApiPost
  • 技术描述:
    1. 通过扒取百度网盘的静态资源,为项目UI 界面提高素材
    2. 采用 ApiPost 接口调试工具查看接口返回数据结构,并编写相对应的接口文档
    3. 通过配置URL Scheme实现外部对 APP 呼起,并跳转到相对应页面
    4. 通过重写原有的部分 Widget 源码,实现项目自定义主题 UI 样式,以及解决HTTPS三次握手失败、携带用户凭证的问题

项目结构 🌲

lj_netdisk
├── README.md                                    // 项目文档
├── analysis_options.yaml
├── android
├── build
├── ios
├── lib                                          // 核心代码
   ├── assets                                   // 静态资源
   ├── common                                   // 公共数据
   ├── config                                   // 全局配置
   ├── generated_plugin_registrant.dart
   ├── main.dart                                // 启动文件
   ├── models                                   // 结构模型
   ├── network                                  // 网络请求
   ├── project_router.dart                      // 项目路由
   ├── styles                                   // 全局样式
   ├── utils                                    // 工具类
   ├── views                                    // 页面视图
   └── widget                                   // Widget
├── lj_netdisk.iml
├── pubspec.lock
├── pubspec.yaml                                 // 相关依赖配置
├── test
└── web

问题记录 🤔

1. 请求图片携带用户凭证、忽略证书问题

新建NetworkImageSSL 工具类:

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui show instantiateImageCodec, Codec;

import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart';

/// Image.network方法显示HTTPS图片时忽略证书
class NetworkImageSSL extends ImageProvider<NetworkImageSSL> {

  const NetworkImageSSL(this.url, {
    this.scale = 1.0,
    required this.headers,
    this.callback
  });

  final String url;

  final double scale;

  final Map<String, String> headers;

  final VoidCallback? callback;

  @override
  Future<NetworkImageSSL> obtainKey(ImageConfiguration configuration) {
    return SynchronousFuture<NetworkImageSSL>(this);
  }

  @override
  ImageStreamCompleter load(NetworkImageSSL key, DecoderCallback decode) {
    return MultiFrameImageStreamCompleter(codec: _loadAsync(key), scale: key.scale);
  }

  static final HttpClient _httpClient = HttpClient()
    ..badCertificateCallback =
    ((X509Certificate cert, String host, int port) => true);

  Future<ui.Codec> _loadAsync(NetworkImageSSL key) async {
    assert(key == this);

    final Uri resolved = Uri.base.resolve(key.url);
    final HttpClientRequest request = await _httpClient.getUrl(resolved);
    headers.forEach((String name, String value) {
      request.headers.add(name, value);
    });
    final HttpClientResponse response = await request.close();

    if (response.statusCode != HttpStatus.ok) {
      throw Exception(
          'HTTP请求失败,状态码: ${response.statusCode}, $resolved');
    }

    final Uint8List bytes = await consolidateHttpClientResponseBytes(response);
    if (bytes.lengthInBytes == 0) {
      throw Exception('NetworkImageSSL是一个空文件: $resolved');
    }

    // 成功则执行
    if (callback != null) callback!();

    return await ui.instantiateImageCodec(bytes);
  }

  @override
  bool operator ==(dynamic other) {
    if (other.runtimeType != runtimeType) return false;
    final NetworkImageSSL typedOther = other;
    return url == typedOther.url && scale == typedOther.scale;
  }

  @override
  int get hashCode => hashValues(url, scale);

  @override
  String toString() => '$runtimeType("$url", scale: $scale)';
}

使用:

Image(
  image: NetworkImageSSL(
    widget.imageUrl,      // 图片地址
    headers: headers,     // 携带用户凭证
    callback: () {
      ....
    }
  ),
);

2. 文件上传,并显示进度条

import 'dart:convert';

import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:lj_netdisk/config/network_config.dart';
import 'package:lj_netdisk/utils/tools/local_storage.dart';

class NetWorkRequest {

  /// Dio 请求实例
  static final Dio _dio = Dio(BaseOptions(
    baseUrl: NetWorkConfig.baseUrl,
    connectTimeout: NetWorkConfig.connectTimeout,
    receiveTimeout: NetWorkConfig.receiveTimeout
  ))
  ..interceptors.add(InterceptorsWrapper(
    onRequest: (RequestOptions options, RequestInterceptorHandler handler) async {
      // 请求截拦
      handler.next(options);
    },
    onResponse: (Response response, ResponseInterceptorHandler handler) {
      // 响应截拦
      handler.next(response);
    },
    onError: (err, handle) {
      // 错误截拦
      handle.next(err);
    },
  ));


  // 文件上传
  // url - 上传的地址
  // filePath - 本地文件路径
  // progressCallback - 上传进度变化时的回调,用来实现进度条
  static Future<Map<String, dynamic>> uploadFile({
    required String url,
    required String filePath,
    Map<String, dynamic>? headers,
    Map<String, dynamic>? body,
    required Function? progressCallback
  }) async {
    // 忽略 HTTPS 证书异常
    (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client){
      client.badCertificateCallback=(cert, host, port){
        return true;
      };
    };

    Map<String, dynamic> data = Map.of(body ?? {});
    data['files'] = await MultipartFile.fromFile(filePath);
    FormData formData = FormData.fromMap(data);   //  form data上传文件
    CancelToken cancelToken = CancelToken();
    Response response = await _dio.post(
        url,
        data: formData,
        options: Options(headers: headers),
        onSendProgress: (int count, int data) {
          if (progressCallback != null) {
            progressCallback(count, data, cancelToken);
          }
        }
    );
    return json.decode(response.data);
  }
}

效果演示 🔥

APP 启动页

App 启动页(一)

用户登录页

App 登录页(二)

APP 首页

App 首页(三)

上传图片

App 文件上传(四)

图片预览

App 图片预览(五)

搜索文件

App 文件搜索(六)

个人中心

App 个人中心(七)

修改中心

App 修改中心(八)

免责声明 👊

本项目的所有图片资源、UI 设计以及软件仅用于个人学习开发测试,所有 百度网盘 百度 相关字样版权属于 北京百度网讯科技有限公司,勿用于商业及非法用途,如产生法律纠纷与本人无关。

如此项目造成侵权损失,请联系本人删除:2361954836@qq.com

MIT License Copyright (c) 2022 shaodong-wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

Flutter,Dart,APP,跨平台,基于 Flutter 跨平台框架开发的网盘类移动端 APP 展开 收起
Dart 等 4 种语言
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Dart
1
https://gitee.com/shaodong-wu/LJ_NetDisk.git
git@gitee.com:shaodong-wu/LJ_NetDisk.git
shaodong-wu
LJ_NetDisk
LJ_NetDisk
main

搜索帮助