提交 be415998 编写于 作者: L linusflow

Merge branch 'master' of https://github.com/didi/DoraemonKit

# Release Notes
### 3.0.7
1、DoKit iOS github issues bug fixed
### 3.0.4
1、DoKit iOS端文件同步助手正式上线
### 3.0.2
1、支持每一个内置Kit,进行位置重排,添加删除某一个Kit
......@@ -242,4 +245,4 @@
3、性能工具:帧率、CPU、内存、流量、自定义
4、视觉工具:颜色吸管、组件检查、对齐标尺
\ No newline at end of file
4、视觉工具:颜色吸管、组件检查、对齐标尺
......@@ -7,7 +7,7 @@
Pod::Spec.new do |s|
s.name = 'DoraemonKit'
s.version = '3.0.6'
s.version = '3.0.7'
s.summary = 'iOS各式各样的工具集合'
s.description = <<-DESC
iOS各式各样的工具集合 Desc
......
## [0.2.14] - methodchannel增加黑名单过滤
## [0.2.13] - 修复网络监控会影响非文本请求内容响应的问题
## [0.2.12] - 修改页面层级,现在DoKitApp将以Stack存放用户传入的Widget,防止各种InheritedWidget影响到用户Widget
## [0.2.11] - 修复一些UI异常问题;日志模块增加错误信息过滤,防止被错误日志冲刷掉;
## [0.2.10] - 修复DoKitApp某些case下获取高度为0的异常.
## [0.2.10] - 修复DoKitApp某些case下获取高度为0的异常.
## [0.2.9] - 修改DoKitApp类型,自定义Overlay容器防止各种InheritedWidget使用异常.
## [0.2.8] - 修复网络请求返回结果乱码问题;增加method—channel耗时统计;日志/方法通道/网络请求增加清空按钮.
## [0.2.7] - 网络请求增加RequestHeaders信息展示,增加非文本类型的返回结果size展示.
......
......@@ -64,6 +64,7 @@ appCreator | DoKitAppCreator | 异步返回根布局 | 同上
useInRelease | bool |是否在release模式下显示DoKit | x
logCallback | LogCallback | 调用print方法打印日志时被回调 | x
exceptionCallback | ExceptionCallback | 异常回调 | x
methodChannelBlackList | List<String> | 过滤方法通道的黑名单 | x
releaseAction | Function | release模式下执行该函数,该值为空则会直接调用系统的runApp |x
......
310a81ea87d5214a76b45c32814582e1
\ No newline at end of file
d4d880dcbf7794a0d22fc1a36580d2b3
\ No newline at end of file
......@@ -2,10 +2,14 @@ PODS:
- Flutter (1.0.0)
- package_info (0.0.1):
- Flutter
- path_provider (0.0.1):
- Flutter
- path_provider_linux (0.0.1):
- Flutter
- path_provider_windows (0.0.1):
- Flutter
- sensors (0.0.1):
- Flutter
- shared_preferences (0.0.1):
- Flutter
- shared_preferences_linux (0.0.1):
......@@ -20,8 +24,10 @@ PODS:
DEPENDENCIES:
- Flutter (from `Flutter`)
- package_info (from `.symlinks/plugins/package_info/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`)
- path_provider_windows (from `.symlinks/plugins/path_provider_windows/ios`)
- sensors (from `.symlinks/plugins/sensors/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`)
- shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`)
......@@ -33,10 +39,14 @@ EXTERNAL SOURCES:
:path: Flutter
package_info:
:path: ".symlinks/plugins/package_info/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
path_provider_linux:
:path: ".symlinks/plugins/path_provider_linux/ios"
path_provider_windows:
:path: ".symlinks/plugins/path_provider_windows/ios"
sensors:
:path: ".symlinks/plugins/sensors/ios"
shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios"
shared_preferences_linux:
......@@ -51,8 +61,10 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d
path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4
path_provider_windows: a2b81600c677ac1959367280991971cb9a1edb3b
sensors: 84eb7a30e47a649e4172b71d6e81be614c280336
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78
shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087
......
......@@ -10,17 +10,26 @@ import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:dokit/dokit.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
void main() {
List<String> blackList = [
'plugins.flutter.io/sensors/gyroscope',
'plugins.flutter.io/sensors/user_accel',
'plugins.flutter.io/sensors/accelerometer'
];
DoKit.runApp(
app: DoKitApp(MyApp()),
useInRelease: true,
logCallback: (log) {
String i = log;
},
methodChannelBlackList: blackList,
exceptionCallback: (obj, trace) {
print('ttt$obj');
});
......@@ -117,6 +126,20 @@ class _DoKitTestPageState extends State<DoKitTestPage> {
onPressed: mockHttpGet,
),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(4)),
color: Color(0xffcccccc)),
margin: EdgeInsets.only(bottom: 30),
child: FlatButton(
child: Text('Test Download',
style: TextStyle(
color: Color(0xff000000),
fontSize: 18,
)),
onPressed: testDownload,
),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(4)),
......@@ -178,40 +201,35 @@ class _DoKitTestPageState extends State<DoKitTestPage> {
Timer timer;
// downloadFile(String url, {String filename}) async {
// var httpClient = http.Client();
// var request = new http.Request('GET', Uri.parse(url));
// var response = httpClient.send(request);
// String dir = '/test/';
//
// List<List<int>> chunks = new List();
// int downloaded = 0;
//
// response.asStream().listen((http.StreamedResponse r) {
//
// r.stream.listen((List<int> chunk) {
// // Display percentage of completion
// debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
//
// chunks.add(chunk);
// downloaded += chunk.length;
// }, onDone: () async {
// // Display percentage of completion
// debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
//
// // Save the file
// // File file = new File('$dir/$filename');
// // final Uint8List bytes = Uint8List(r.contentLength);
// // int offset = 0;
// // for (List<int> chunk in chunks) {
// // bytes.setRange(offset, offset + chunk.length, chunk);
// // offset += chunk.length;
// // }
// // await file.writeAsBytes(bytes);
// return;
// });
// });
// }
testDownload() async {
String url =
'https://pt-starfile.didistatic.com/static/starfile/node20210220/895f1e95e30aba5dd56d6f2ccf768b57/GjzGU0Pvv11613804530384.zip';
String savePath = await getPhoneLocalPath();
String zipName = 'test.zip';
Dio dio = new Dio();
print("$savePath/$zipName");
Response response = await dio.download(url, "$savePath/$zipName",
onReceiveProgress: (received, total) {
if (total != -1) {
// 当前下载的百分比
// print((received / total * 100).toStringAsFixed(0) + "%");
// print("received=$received total=$total");
if (received == total) {
print("下载完成 ✅ ");
}
} else {}
});
}
///获取手机的存储目录路径
///getExternalStorageDirectory() 获取的是 android 的外部存储 (External Storage)
/// getApplicationDocumentsDirectory 获取的是 ios 的Documents` or `Downloads` 目录
Future<String> getPhoneLocalPath() async {
final directory = Theme.of(context).platform == TargetPlatform.android
? await getExternalStorageDirectory()
: await getApplicationDocumentsDirectory();
return directory.path;
}
void testMethodChannel() {
timer?.cancel();
......
......@@ -11,6 +11,10 @@ dependencies:
sdk: flutter
dokit:
path: ..
dio: 3.0.10
path_provider: 1.6.0
dev_dependencies:
flutter_test:
sdk: flutter
......
......@@ -5,7 +5,6 @@ import 'package:dokit/ui/dokit_btn.dart';
import 'package:dokit/ui/dokit_app.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:core';
import 'package:flutter/widgets.dart' as dart;
import 'package:dokit/kit/kit_page.dart';
......@@ -38,6 +37,7 @@ class DoKit {
bool useInRelease = false,
LogCallback logCallback,
ExceptionCallback exceptionCallback,
List<String> methodChannelBlackList=const [],
Function releaseAction}) async {
assert(
app != null || appCreator != null, 'app and appCreator are both null');
......@@ -53,6 +53,7 @@ class DoKit {
}
return;
}
blackList = methodChannelBlackList;
runZoned(
() async => {
_ensureDoKitBinding(useInRelease: useInRelease),
......
......@@ -7,6 +7,8 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
List<String> blackList = [];
class DoKitWidgetsFlutterBinding extends WidgetsFlutterBinding
with DoKitServicesBinding {
static WidgetsBinding ensureInitialized() {
......@@ -43,6 +45,9 @@ class DoKitBinaryMessenger extends BinaryMessenger {
@override
Future<void> handlePlatformMessage(String channel, ByteData data, callback) {
ChannelInfo info = saveMessage(channel, data, false);
if (info == null) {
return origin.handlePlatformMessage(channel, data, callback);
}
PlatformMessageResponseCallback wrapper = (ByteData data) {
resolveResult(info, data);
callback(data);
......@@ -53,6 +58,9 @@ class DoKitBinaryMessenger extends BinaryMessenger {
@override
Future<ByteData> send(String channel, ByteData message) async {
ChannelInfo info = saveMessage(channel, message, true);
if (info == null) {
return origin.send(channel, message);
}
ByteData result = await origin.send(channel, message);
resolveResult(info, result);
return result;
......@@ -67,7 +75,7 @@ class DoKitBinaryMessenger extends BinaryMessenger {
} else if (info.messageCodec != null) {
info.results = info.messageCodec.decodeMessage(result);
info.endTimestamp = new DateTime.now().millisecondsSinceEpoch;
}else{
} else {
info.endTimestamp = new DateTime.now().millisecondsSinceEpoch;
}
}
......@@ -82,6 +90,9 @@ class DoKitBinaryMessenger extends BinaryMessenger {
if (kit == null) {
return null;
}
if (blackList != null && blackList.contains(name)) {
return null;
}
ChannelInfo info;
try {
info = filterSystemChannel(name, data, send);
......
......@@ -497,20 +497,21 @@ class DoKitHttpClientResponse implements HttpClientResponse {
@override
StreamSubscription<List<int>> listen(void Function(List<int> event) onData,
{Function onError, void Function() onDone, bool cancelOnError}) {
if (!isTextResponse()) {
recordResponse(
statusCode, "返回结果不支持解析", headers?.toString(), contentLength);
return origin.listen(onData,
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
}
void onDataWrapper(List<int> result) {
onData(result);
try {
if (isTextResponse()) {
if (getEncoding() != null) {
recordResponse(statusCode, getEncoding().decode(result),
headers?.toString(), contentLength);
} else {
recordResponse(
statusCode, "返回结果解析失败", headers?.toString(), contentLength);
}
if (getEncoding() != null) {
recordResponse(statusCode, getEncoding().decode(result),
headers?.toString(), contentLength);
} else {
recordResponse(
statusCode, "返回结果不支持解析", headers?.toString(), contentLength);
statusCode, "返回结果解析失败", headers?.toString(), contentLength);
}
} catch (e) {
recordResponse(
......@@ -604,27 +605,27 @@ class DoKitHttpClientResponse implements HttpClientResponse {
@override
Stream<S> transform<S>(StreamTransformer<List<int>, S> streamTransformer) {
Stream s = origin.transform(streamTransformer);
if (!isTextResponse()) {
recordResponse(
statusCode, "返回结果不支持解析", headers?.toString(), contentLength);
return s;
}
s = s.asBroadcastStream();
s.listen((event) {
if (isTextResponse()) {
if (event is Uint8List) {
Uint8List result = event;
if (getEncoding() != null) {
recordResponse(statusCode, getEncoding().decode(result.toList()),
headers?.toString(), event.length);
} else {
recordResponse(
statusCode, "返回结果解析失败", headers?.toString(), contentLength);
}
} else if (event is String) {
recordResponse(statusCode, event, headers?.toString(), contentLength);
if (event is Uint8List) {
Uint8List result = event;
if (getEncoding() != null) {
recordResponse(statusCode, getEncoding().decode(result.toList()),
headers?.toString(), event.length);
} else {
recordResponse(statusCode, 'unknown type:${event.runtimeType}',
headers?.toString(), contentLength);
recordResponse(
statusCode, "返回结果解析失败", headers?.toString(), contentLength);
}
} else if (event is String) {
recordResponse(statusCode, event, headers?.toString(), contentLength);
} else {
recordResponse(
statusCode, "返回结果不支持解析", headers?.toString(), contentLength);
recordResponse(statusCode, 'unknown type:${event.runtimeType}',
headers?.toString(), contentLength);
}
});
return s;
......
......@@ -18,34 +18,21 @@ class ResidentPage extends StatefulWidget {
class ResidentPageState extends State<ResidentPage> {
Widget getPage() {
if (ResidentPage.tag == KitPageManager.KIT_ALL) {
return KitPage();
}
if (ApmKitManager.instance.getKit(ResidentPage.tag) != null) {
return ApmKitManager.instance
.getKit(ResidentPage.tag)
.createDisplayPage();
}
if (CommonKitManager.instance.getKit(ResidentPage.tag) != null) {
return CommonKitManager.instance
.getKit(ResidentPage.tag)
.createDisplayPage();
}
return Container(
alignment: Alignment.center,
child:
Text('无数据', style: TextStyle(color: Color(0xff999999), fontSize: 20)),
);
Widget page;
page ??=
ApmKitManager.instance.getKit(ResidentPage.tag)?.createDisplayPage();
page ??=
CommonKitManager.instance.getKit(ResidentPage.tag)?.createDisplayPage();
page ??= KitPage();
return page;
}
String getTitle() {
if (ApmKitManager.instance.getKit(ResidentPage.tag) != null) {
return ApmKitManager.instance.getKit(ResidentPage.tag).getKitName();
}
if (CommonKitManager.instance.getKit(ResidentPage.tag) != null) {
return CommonKitManager.instance.getKit(ResidentPage.tag).getKitName();
}
return 'DoKit';
String title;
title ??= ApmKitManager.instance.getKit(ResidentPage.tag)?.getKitName();
title ??= CommonKitManager.instance.getKit(ResidentPage.tag)?.getKitName();
title ??= 'DoKit';
return title;
}
_tapListener(String current) {
......
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.13"
args:
dependency: transitive
description:
name: args
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.6.0"
async:
dependency: transitive
description:
name: async
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.1"
version: "2.5.0-nullsafety.1"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
charcode:
version: "2.1.0-nullsafety.1"
characters:
dependency: transitive
description:
name: charcode
name: characters
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.3"
collection:
version: "1.1.0-nullsafety.3"
charcode:
dependency: transitive
description:
name: collection
name: charcode
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.14.12"
convert:
version: "1.2.0-nullsafety.1"
clock:
dependency: transitive
description:
name: convert
name: clock
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.1"
crypto:
version: "1.1.0-nullsafety.1"
collection:
dependency: transitive
description:
name: crypto
name: collection
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.4"
version: "1.15.0-nullsafety.3"
date_format:
dependency: "direct main"
description:
......@@ -64,6 +50,13 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.9"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0-nullsafety.1"
ffi:
dependency: transitive
description:
......@@ -93,13 +86,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
image:
dependency: transitive
description:
name: image
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.12"
intl:
dependency: transitive
description:
......@@ -113,14 +99,14 @@ packages:
name: matcher
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.12.6"
version: "0.12.10-nullsafety.1"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.8"
version: "1.3.0-nullsafety.3"
package_info:
dependency: "direct main"
description:
......@@ -134,7 +120,7 @@ packages:
name: path
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.6.4"
version: "1.8.0-nullsafety.1"
path_provider_linux:
dependency: transitive
description:
......@@ -156,13 +142,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.4+3"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.0"
platform:
dependency: transitive
description:
......@@ -184,13 +163,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.13"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.3"
shared_preferences:
dependency: "direct main"
description:
......@@ -244,56 +216,56 @@ packages:
name: source_span
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.7.0"
version: "1.8.0-nullsafety.2"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.9.3"
version: "1.10.0-nullsafety.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
version: "2.1.0-nullsafety.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.5"
version: "1.1.0-nullsafety.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
version: "1.2.0-nullsafety.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.15"
version: "0.2.19-nullsafety.2"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.6"
version: "1.3.0-nullsafety.3"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.8"
version: "2.1.0-nullsafety.3"
vm_service:
dependency: "direct main"
description:
......@@ -315,13 +287,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.6.1"
sdks:
dart: ">=2.7.0 <3.0.0"
dart: ">=2.10.0-110 <2.11.0"
flutter: ">=1.17.0 <2.0.0"
name: dokit
description: 开发工具集
version: 0.2.12
version: 0.2.14
homepage: https://www.dokit.cn/#/index/home
......
......@@ -27,8 +27,8 @@
<img src="https://javer.oss-cn-shanghai.aliyuncs.com/doraemon/github/DoraemonKit_github.png" width = "150" height = "150" alt="DoraemonKit" align=left />
<img src="https://img.shields.io/github/license/didi/DoraemonKit.svg" align=left />
<img src="https://img.shields.io/badge/Android-3.3.5-blue.svg" align=left />
<img src="https://img.shields.io/badge/iOS-3.0.4-yellow.svg" align=left />
<img src="https://img.shields.io/badge/Flutter-0.2.12-blue.svg" align=left />
<img src="https://img.shields.io/badge/iOS-3.0.7-yellow.svg" align=left />
<img src="https://img.shields.io/badge/Flutter-0.2.14-blue.svg" align=left />
<img src="https://img.shields.io/badge/miniapp-0.0.1-red.svg" align=left />
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" align=left />
</div>
......@@ -238,7 +238,7 @@ tips : 如果使用我们滴滴优秀的开源跨端方案 [chameleon](https:/
[yixiangboy](https://github.com/yixiangboy)
[jtsky](https://github.com/jtsky)
[LinJZong](https://github.com/LinJZong)
[ydlsl](https://github.com/ydlsl)
[changzuozhen](https://github.com/changzuozhen)
[jayconscious](https://github.com/jayconscious)
**贡献者榜单**
......@@ -270,7 +270,8 @@ tips : 如果使用我们滴滴优秀的开源跨端方案 [chameleon](https:/
[sagdragon](https://github.com/sagdragon)
[ccworld1000](https://github.com/ccworld1000)
[HDB-Li](https://github.com/HDB-Li)
[yu-jianfeng](https://github.com/yu-jianfeng)
[yu-jianfeng](https://github.com/yu-jianfeng)
[ydlsl](https://github.com/ydlsl)
如何成为外部贡献者? 提交有意义的PR,并被采纳。
......
## 介绍
一款面向前端生态的开发工具
### 愿景
让前端开发更美好
### 功能
#### 日志
展示 `Console` 控制台的日志
##### 基础功能
- 支持所有的 `console` 方法
- 支持日志的筛选和清除
- 支持执行简易的 `javascript`命令
##### 进阶功能
- 打通平台侧的日志查看,支持查看多个设备
#### 接口抓取
展示所有的数据请求
##### 基础功能
- 支持抓取常用的接口类型 `xhr``fetch`
- 展示请求的详细内容
- 展示响应的详细内容
##### 进阶功能
- 支持拦截请求,修改数据(平台端进行修改)
- 支持根据请求,快捷添加 Mock 接口 (和平台侧打通)
#### 视图元素查看
展示视图树,展示`Dom`
##### 基础功能
- 展示整个页面的 `Dom`
- 支持展开、关闭、选择(高亮元素)
- 支持查看特定元素的内容
- 查看元素的样式
- 查看元素的盒模型
##### 进阶功能
- 支持切换模式查看元素
- 考虑移动端的交互,点击区域不宜过小
#### 资源查看
展示页面的所有资源请求
##### 基础功能
- 展示`javascript`资源
- 展示`css`资源
- 展示`image`等媒体资源
#### 应用存储
展示当前页面的存储信息
##### 基础功能
- 支持查看并修改 `LocalStorage`
- 支持查看并修改 `SessionStorage`
- 支持查看 `Cookie`
#### 接口Mock
无侵入式 Mock 数据
##### 基础功能
- 支持无侵入式一键 Mock
- 支持自动同步真实请求数据到平台侧,并与快速创建
#### 屏幕录制 & 回放
> 功能设计中
#### 自动化测试
> 功能设计中
......@@ -113,12 +113,17 @@ typedef NS_ENUM(NSUInteger, DoraemonManagerPluginType) {
@property (nonatomic, copy) NSString *pId; //产品id 平台端的工具必须填写
@property (nonatomic, copy) NSString *mockDomain; //产品mockDomain 非必填 默认mock.dokit.cn
@property (nonatomic, assign) BOOL autoDock; //dokit entry icon support autoDock,deffault yes
- (void)install;
//带有平台端功能的s初始化方式
// 带有平台端功能的s初始化方式
- (void)installWithPid:(NSString *)pId;
// 自定义平台mockDomain初始化方式
- (void)installWithMockDomain:(NSString *)mockDomain;
// 定制起始位置 | 适用正好挡住关键位置
- (void)installWithStartingPosition:(CGPoint) position;
......
......@@ -110,6 +110,11 @@ typedef void (^DoraemonPerformanceBlock)(NSDictionary *);
[self install];
}
- (void)installWithMockDomain:(NSString *)mockDomain{
self.mockDomain = mockDomain;
[self install];
}
- (void)installWithStartingPosition:(CGPoint) position{
_startingPosition = position;
[self installWithCustomBlock:^{
......
......@@ -11,6 +11,7 @@
#import "DoraemonNetFlowManager.h"
#import "DoraemonURLSessionDemux.h"
#import "DoraemonNetworkInterceptor.h"
#import "DoraemonManager.h"
#import "DoraemonMockManager.h"
#import "DoraemonDefine.h"
#import "DoraemonUrlUtil.h"
......@@ -78,8 +79,10 @@ static NSString * const kDoraemonProtocolKey = @"doraemon_protocol_key";
NSMutableURLRequest *mutableReqeust = [request mutableCopy];
[NSURLProtocol setProperty:@YES forKey:kDoraemonProtocolKey inRequest:mutableReqeust];
if ([[DoraemonMockManager sharedInstance] needMock:request]) {
NSString *mockDomain = [DoraemonManager shareInstance].mockDomain ? [DoraemonManager shareInstance].mockDomain : @"https://mock.dokit.cn/";
NSString *mockSceneUrl = [mockDomain stringByAppendingString:@"api/app/scene/%@"];
NSString *sceneId = [[DoraemonMockManager sharedInstance] getSceneId:request];
NSString *urlString = [NSString stringWithFormat:@"https://mock.dokit.cn/api/app/scene/%@",sceneId];
NSString *urlString = [NSString stringWithFormat:mockSceneUrl, sceneId];
DoKitLog(@"MOCK URL == %@",urlString);
mutableReqeust = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
dispatch_async(dispatch_get_main_queue(), ^{
......@@ -98,8 +101,10 @@ static NSString * const kDoraemonProtocolKey = @"doraemon_protocol_key";
});
}else if(DoraemonWeakNetwork_WeakSpeed == [[DoraemonNetworkInterceptor shareInstance].weakDelegate weakNetSelecte]){
DoKitLog(@"yd WeakUpFlow Net");
[[DoraemonNetworkInterceptor shareInstance].weakDelegate handleWeak:[DoraemonUrlUtil getHttpBodyFromRequest:self.request] isDown:NO];
[self.task resume];
[[DoraemonNetFlowManager shareInstance] httpBodyFromRequest:self.request bodyCallBack:^(NSData *body) {
[[DoraemonNetworkInterceptor shareInstance].weakDelegate handleWeak:body isDown:NO];
[self.task resume];
}];
}else{
[self.task resume];
}
......
......@@ -28,6 +28,6 @@
@property (nonatomic, copy) NSString *topVc;//流量触发时候的顶层vc
+ (DoraemonNetFlowHttpModel *)dealWithResponseData:(NSData *)responseData response:(NSURLResponse*)response request:(NSURLRequest *)request;
+ (void)dealWithResponseData:(NSData *)responseData response:(NSURLResponse*)response request:(NSURLRequest *)request complete:(void (^)(DoraemonNetFlowHttpModel *model))complete;
@end
......@@ -6,24 +6,19 @@
//
#import "DoraemonNetFlowHttpModel.h"
#import "DoraemonNetFlowManager.h"
#import "NSURLRequest+Doraemon.h"
#import "DoraemonUrlUtil.h"
@implementation DoraemonNetFlowHttpModel
+ (DoraemonNetFlowHttpModel *)dealWithResponseData:(NSData *)responseData response:(NSURLResponse*)response request:(NSURLRequest *)request{
+ (void)dealWithResponseData:(NSData *)responseData response:(NSURLResponse*)response request:(NSURLRequest *)request complete:(void (^)(DoraemonNetFlowHttpModel *model))complete {
DoraemonNetFlowHttpModel *httpModel = [[DoraemonNetFlowHttpModel alloc] init];
//request
httpModel.request = request;
httpModel.requestId = request.requestId;
httpModel.url = [request.URL absoluteString];
httpModel.method = request.HTTPMethod;
NSData *httpBody = [DoraemonUrlUtil getHttpBodyFromRequest:request];
httpModel.requestBody = [DoraemonUrlUtil convertJsonFromData:httpBody];
httpModel.uploadFlow = [NSString stringWithFormat:@"%zi",[DoraemonUrlUtil getRequestLength:request]];
//response
httpModel.mineType = response.MIMEType;
httpModel.response = response;
......@@ -33,12 +28,12 @@
httpModel.responseBody = [DoraemonUrlUtil convertJsonFromData:responseData];
httpModel.totalDuration = [NSString stringWithFormat:@"%fs",[[NSDate date] timeIntervalSince1970] - request.startTime.doubleValue];
httpModel.downFlow = [NSString stringWithFormat:@"%lli",[DoraemonUrlUtil getResponseLength:(NSHTTPURLResponse *)response data:responseData]];
return httpModel;
[[DoraemonNetFlowManager shareInstance] httpBodyFromRequest:request bodyCallBack:^(NSData *body) {
httpModel.requestBody = [DoraemonUrlUtil convertJsonFromData:body];
NSUInteger length = [DoraemonUrlUtil getHeadersLengthWithRequest:request] + [body length];
httpModel.uploadFlow = [NSString stringWithFormat:@"%zi", length];
complete(httpModel);
}];
}
@end
......@@ -7,6 +7,8 @@
#import <Foundation/Foundation.h>
typedef void(^HttpBodyCallBack)(NSData *body);
@interface DoraemonNetFlowManager : NSObject
+ (DoraemonNetFlowManager *)shareInstance;
......@@ -16,4 +18,6 @@
- (void)canInterceptNetFlow:(BOOL)enable;
- (void)httpBodyFromRequest:(NSURLRequest *)request bodyCallBack:(HttpBodyCallBack)complete;
@end
......@@ -13,7 +13,10 @@
#import "UIViewController+Doraemon.h"
#import "DoraemonHealthManager.h"
@interface DoraemonNetFlowManager() <DoraemonNetworkInterceptorDelegate>
@interface DoraemonNetFlowManager() <DoraemonNetworkInterceptorDelegate, NSStreamDelegate>
@property (nonatomic, copy) HttpBodyCallBack bodyCallBack;
@property (nonatomic, strong) NSMutableData *bodyData;
@end
......@@ -40,21 +43,79 @@
}
}
- (void)httpBodyFromRequest:(NSURLRequest *)request bodyCallBack:(HttpBodyCallBack)complete {
NSData *httpBody = nil;
if (request.HTTPBody) {
httpBody = request.HTTPBody;
complete(httpBody);
return;
}
if ([request.HTTPMethod isEqualToString:@"POST"]) {
NSInputStream *stream = request.HTTPBodyStream;
[stream setDelegate:self];
self.bodyCallBack = complete;
[stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[stream open];
} else {
complete(httpBody);
}
}
#pragma mark -- NSStreamDelegate
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
switch (eventCode) {
case NSStreamEventHasBytesAvailable:
{
if (!self.bodyData) {
self.bodyData = [NSMutableData data];
}
uint8_t buf[1024];
NSInteger len = 0;
len = [(NSInputStream *)aStream read:buf maxLength:1024];
if (len) {
[self.bodyData appendBytes:(const void *)buf length:len];
}
}
break;
case NSStreamEventErrorOccurred:
{
NSError * error = [aStream streamError];
NSString * errorInfo = [NSString stringWithFormat:@"Failed while reading stream; error '%@' (code %ld)", error.localizedDescription, error.code];
NSLog(@"%@",errorInfo);
}
break;
case NSStreamEventEndEncountered:
{
[aStream close];
[aStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
aStream = nil;
if (self.bodyCallBack) {
self.bodyCallBack([self.bodyData copy]);
}
self.bodyData = nil;
}
break;
default:
break;
}
}
#pragma mark -- DoraemonNetworkInterceptorDelegate
- (void)doraemonNetworkInterceptorDidReceiveData:(NSData *)data response:(NSURLResponse *)response request:(NSURLRequest *)request error:(NSError *)error startTime:(NSTimeInterval)startTime {
DoraemonNetFlowHttpModel *httpModel = [DoraemonNetFlowHttpModel dealWithResponseData:data response:response request:request];
if (!response) {
httpModel.statusCode = error.localizedDescription;
}
httpModel.startTime = startTime;
httpModel.endTime = [[NSDate date] timeIntervalSince1970];
httpModel.totalDuration = [NSString stringWithFormat:@"%f",[[NSDate date] timeIntervalSince1970] - startTime];
httpModel.topVc = NSStringFromClass([[UIViewController topViewControllerForKeyWindow] class]);
[[DoraemonNetFlowDataSource shareInstance] addHttpModel:httpModel];
[[DoraemonHealthManager sharedInstance] addHttpModel:httpModel];
[DoraemonNetFlowHttpModel dealWithResponseData:data response:response request:request complete:^(DoraemonNetFlowHttpModel *httpModel) {
if (!response) {
httpModel.statusCode = error.localizedDescription;
}
httpModel.startTime = startTime;
httpModel.endTime = [[NSDate date] timeIntervalSince1970];
httpModel.totalDuration = [NSString stringWithFormat:@"%f",[[NSDate date] timeIntervalSince1970] - startTime];
httpModel.topVc = NSStringFromClass([[UIViewController topViewControllerForKeyWindow] class]);
[[DoraemonNetFlowDataSource shareInstance] addHttpModel:httpModel];
[[DoraemonHealthManager sharedInstance] addHttpModel:httpModel];
}];
}
- (BOOL)shouldIntercept {
......
......@@ -13,7 +13,9 @@
+ (NSDictionary *)convertDicFromData:(NSData *)data;
+ (NSUInteger)getRequestLength:(NSURLRequest *)request;
+ (NSUInteger)getHeadersLengthWithRequest:(NSURLRequest *)request;
+ (void)requestLength:(NSURLRequest *)request callBack:(void (^)(NSUInteger))callBack;
+ (NSUInteger)getHeadersLength:(NSDictionary *)headers ;
......@@ -21,6 +23,4 @@
+ (int64_t)getResponseLength:(NSHTTPURLResponse *)response data:(NSData *)responseData;
+ (NSData *)getHttpBodyFromRequest:(NSURLRequest *)request;
@end
......@@ -6,6 +6,7 @@
//
#import "DoraemonUrlUtil.h"
#import "DoraemonNetFlowManager.h"
@implementation DoraemonUrlUtil
......@@ -39,7 +40,15 @@
return jsonObj;
}
+ (NSUInteger)getRequestLength:(NSURLRequest *)request{
+ (void)requestLength:(NSURLRequest *)request callBack:(void (^)(NSUInteger))callBack {
NSUInteger headersLength = [self getHeadersLengthWithRequest:request];
[[DoraemonNetFlowManager shareInstance] httpBodyFromRequest:request bodyCallBack:^(NSData *body) {
NSUInteger bodyLength = [body length];
callBack(headersLength + bodyLength);
}];
}
+ (NSUInteger)getHeadersLengthWithRequest:(NSURLRequest *)request {
NSDictionary<NSString *, NSString *> *headerFields = request.allHTTPHeaderFields;
NSDictionary<NSString *, NSString *> *cookiesHeader = [self getCookies:request];
if (cookiesHeader.count) {
......@@ -47,11 +56,7 @@
[headerFieldsWithCookies addEntriesFromDictionary:cookiesHeader];
headerFields = [headerFieldsWithCookies copy];
}
NSUInteger headersLength = [self getHeadersLength:headerFields];
NSData *httpBody = [[self class] getHttpBodyFromRequest:request];
NSUInteger bodyLength = [httpBody length];
return headersLength + bodyLength;
return [self getHeadersLength:headerFields];
}
+ (NSUInteger)getHeadersLength:(NSDictionary *)headers {
......@@ -95,28 +100,4 @@
return responseLength;
}
+ (NSData *)getHttpBodyFromRequest:(NSURLRequest *)request{
NSData *httpBody;
if (request.HTTPBody) {
httpBody = request.HTTPBody;
}else{
if ([request.HTTPMethod isEqualToString:@"POST"]) {
if (!request.HTTPBody) {
uint8_t d[1024] = {0};
NSInputStream *stream = request.HTTPBodyStream;
NSMutableData *data = [[NSMutableData alloc] init];
[stream open];
while ([stream hasBytesAvailable]) {
NSInteger len = [stream read:d maxLength:1024];
if (len > 0 && stream.streamError == nil) {
[data appendBytes:(void *)d length:len];
}
}
httpBody = [data copy];
[stream close];
}
}
}
return httpBody;
}
@end
......@@ -115,7 +115,9 @@
#pragma mark -- DoraemonNetworkInterceptorDelegate
- (void)doraemonNetworkInterceptorDidReceiveData:(NSData *)data response:(NSURLResponse *)response request:(NSURLRequest *)request error:(NSError *)error startTime:(NSTimeInterval)startTime {
[[DoraemonWeakNetworkWindow shareInstance] updateFlowValue:[NSString stringWithFormat:@"%zi",[DoraemonUrlUtil getRequestLength:request]] downFlow:[NSString stringWithFormat:@"%lli",[DoraemonUrlUtil getResponseLength:(NSHTTPURLResponse *)response data:data]] fromWeak:NO];
[DoraemonUrlUtil requestLength:request callBack:^(NSUInteger length) {
[[DoraemonWeakNetworkWindow shareInstance] updateFlowValue:[NSString stringWithFormat:@"%zi",length] downFlow:[NSString stringWithFormat:@"%lli",[DoraemonUrlUtil getResponseLength:(NSHTTPURLResponse *)response data:data]] fromWeak:NO];
}];
}
- (BOOL)shouldIntercept {
......
......@@ -59,6 +59,7 @@
- (void)queryMockData:(void(^)(int flag))block{
NSString *pId = [DoraemonManager shareInstance].pId;
NSString *mockDomain = [DoraemonManager shareInstance].mockDomain ? [DoraemonManager shareInstance].mockDomain : @"https://mock.dokit.cn/";
if (pId && pId.length>0) {
NSDictionary *params = @{
@"projectId":pId,
......@@ -68,7 +69,8 @@
};
__weak typeof(self) weakSelf = self;
[DoraemonNetworkUtil getWithUrlString:@"https://mock.dokit.cn/api/app/interface" params:params success:^(NSDictionary * _Nonnull result) {
NSString *mockInterfaceUrl = [mockDomain stringByAppendingString:@"api/app/interface"];
[DoraemonNetworkUtil getWithUrlString:mockInterfaceUrl params:params success:^(NSDictionary * _Nonnull result) {
NSArray *apis = result[@"data"][@"datalist"];
NSMutableArray<DoraemonMockAPIModel *> *mockArray = [[NSMutableArray alloc] init];
NSMutableArray<DoraemonMockUpLoadModel *> *uploadArray = [[NSMutableArray alloc] init];
......@@ -181,7 +183,8 @@
- (DoraemonMockBaseModel *)getSelectedData:(NSURLRequest *)request dataArray:(NSArray *)dataArray{
NSString *path = request.URL.path;
NSString *query = request.URL.query;
NSData *httpBody = [DoraemonUrlUtil getHttpBodyFromRequest:request];
// 这里暂时使用不严谨body match
NSData *httpBody = request.HTTPBody;
NSDictionary *requestBody = [DoraemonUrlUtil convertDicFromData:httpBody];
DoraemonMockBaseModel *selectedApi;
for (DoraemonMockBaseModel *api in dataArray) {
......@@ -329,7 +332,7 @@
NSString *apiId = upload.apiId;
NSString *result = upload.result;
NSString *projectId = [DoraemonManager shareInstance].pId;
NSString *mockDomain = [DoraemonManager shareInstance].mockDomain ? [DoraemonManager shareInstance].mockDomain : @"https://mock.dokit.cn/";
if (projectId && projectId.length > 0) {
if (!result) {
return;
......@@ -340,8 +343,8 @@
@"id":apiId,
@"tempData":result
};
[DoraemonNetworkUtil patchWithUrlString:@"https://mock.dokit.cn/api/app/interface" params:params success:^(NSDictionary * _Nonnull result) {
NSString *mockInterfaceUrl = [mockDomain stringByAppendingString:@"api/app/interface"];
[DoraemonNetworkUtil patchWithUrlString:mockInterfaceUrl params:params success:^(NSDictionary * _Nonnull result) {
[self showToast:DoraemonLocalizedString(@"上传成功") atView:view];
} error:^(NSError * _Nonnull error) {
DoKitLog(@"error == %@",error);
......
......@@ -8,6 +8,7 @@
#import "DoraemonDemoURLProtocol1.h"
#import "DoraemonUrlUtil.h"
#import "DoraemonNetFlowManager.h"
static NSString * const kDoraemonDemoUrlProtocolKey = @"doraemon_demo_url_protocol_1_key";
......@@ -48,10 +49,11 @@ static NSString * const kDoraemonDemoUrlProtocolKey = @"doraemon_demo_url_protoc
- (void)stopLoading{
NSLog(@"11111 == stopLoading");
NSData *httpBody = [DoraemonUrlUtil getHttpBodyFromRequest:self.request];
NSString* requestBody = [DoraemonUrlUtil convertJsonFromData:httpBody];
NSLog(@"11111 == requestBody = %@",requestBody);
[self.connection cancel];
[[DoraemonNetFlowManager shareInstance] httpBodyFromRequest:self.request bodyCallBack:^(NSData *httpBody) {
NSString* requestBody = [DoraemonUrlUtil convertJsonFromData:httpBody];
NSLog(@"11111 == requestBody = %@",requestBody);
[self.connection cancel];
}];
}
......
......@@ -8,6 +8,7 @@
#import "DoraemonDemoURLProtocol2.h"
#import "DoraemonUrlUtil.h"
#import "DoraemonNetFlowManager.h"
static NSString * const kDoraemonDemoUrlProtocol2Key = @"doraemon_demo_url_protocol_2_key";
......@@ -48,10 +49,11 @@ static NSString * const kDoraemonDemoUrlProtocol2Key = @"doraemon_demo_url_proto
- (void)stopLoading{
NSLog(@"22222 == stopLoading");
NSData *httpBody = [DoraemonUrlUtil getHttpBodyFromRequest:self.request];
NSString* requestBody = [DoraemonUrlUtil convertJsonFromData:httpBody];
NSLog(@"22222 == requestBody = %@",requestBody);
[self.connection cancel];
[[DoraemonNetFlowManager shareInstance] httpBodyFromRequest:self.request bodyCallBack:^(NSData *httpBody) {
NSString* requestBody = [DoraemonUrlUtil convertJsonFromData:httpBody];
NSLog(@"22222 == requestBody = %@",requestBody);
[self.connection cancel];
}];
}
......
......@@ -222,10 +222,11 @@
session.requestSerializer = [AFHTTPRequestSerializer serializer];// 请求
session.responseSerializer = [AFHTTPResponseSerializer serializer];// 响应
session.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json",@"text/javascript",@"text/html", nil];
[session GET:@"https://www.taobao.com/" parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
[session GET:@"https://www.taobao.com/" parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSString *string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(@"success %@",string);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"failure");
}];
......@@ -238,7 +239,7 @@
}
- (void)netForAFNetworking2{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];// 请求
manager.responseSerializer = [AFHTTPResponseSerializer serializer];// 响应
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json",@"text/javascript",@"text/html", nil];
......@@ -249,10 +250,10 @@
// NSLog(@"请求失败");
// }];
[manager POST:@"https://www.taobao.com/" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
[manager POST:@"https://www.taobao.com/" parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSString *string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(@"success %@",string);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"failure");
}];
}
......
......@@ -130,14 +130,15 @@
// NSLog(@"请求失败");
// }];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];// 请求
manager.responseSerializer = [AFHTTPResponseSerializer serializer];// 响应
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json",@"text/javascript",@"text/html", nil];
[manager GET:@"https://www.taobao.com/" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
[manager GET:@"https://www.taobao.com/" parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSString *string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(@"request success %@",string);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"request failure");
}];
}
......
......@@ -20,7 +20,7 @@ target :'DoraemonKitDemo' do
#pod 'DoraemonKit', :subspecs => ['Core','WithLogger','WithGPS','WithLoad','WithWeex', 'WithDatabase', 'WithMLeaksFinder'], :path => '../../'
#pod 'DoraemonKit', :subspecs => ['Core'], :path => '../../'
pod 'DoraemonKit', :subspecs => ['Core','WithLogger','WithGPS','WithLoad','WithDatabase', 'WithMLeaksFinder','WithWeex'], :path => '../../'
pod 'AFNetworking','2.6.3'
pod 'AFNetworking'
pod 'SDWebImage'
pod 'SocketRocket', '~> 0.5'
pod 'SDWebImageWebPCoder'
......
PODS:
- AFNetworking (2.6.3):
- AFNetworking/NSURLConnection (= 2.6.3)
- AFNetworking/NSURLSession (= 2.6.3)
- AFNetworking/Reachability (= 2.6.3)
- AFNetworking/Security (= 2.6.3)
- AFNetworking/Serialization (= 2.6.3)
- AFNetworking/UIKit (= 2.6.3)
- AFNetworking/NSURLConnection (2.6.3):
- AFNetworking (4.0.1):
- AFNetworking/NSURLSession (= 4.0.1)
- AFNetworking/Reachability (= 4.0.1)
- AFNetworking/Security (= 4.0.1)
- AFNetworking/Serialization (= 4.0.1)
- AFNetworking/UIKit (= 4.0.1)
- AFNetworking/NSURLSession (4.0.1):
- AFNetworking/Reachability
- AFNetworking/Security
- AFNetworking/Serialization
- AFNetworking/NSURLSession (2.6.3):
- AFNetworking/Reachability
- AFNetworking/Security
- AFNetworking/Serialization
- AFNetworking/Reachability (2.6.3)
- AFNetworking/Security (2.6.3)
- AFNetworking/Serialization (2.6.3)
- AFNetworking/UIKit (2.6.3):
- AFNetworking/NSURLConnection
- AFNetworking/Reachability (4.0.1)
- AFNetworking/Security (4.0.1)
- AFNetworking/Serialization (4.0.1)
- AFNetworking/UIKit (4.0.1):
- AFNetworking/NSURLSession
- CocoaLumberjack (3.6.2):
- CocoaLumberjack/Core (= 3.6.2)
- CocoaLumberjack/Core (3.6.2)
- CocoaLumberjack (3.7.0):
- CocoaLumberjack/Core (= 3.7.0)
- CocoaLumberjack/Core (3.7.0)
- DoraemonKit/Core (3.0.6):
- FMDB
- GCDWebServer
......@@ -65,12 +59,12 @@ PODS:
- libwebp/mux (1.1.0):
- libwebp/demux
- libwebp/webp (1.1.0)
- SDWebImage (5.8.4):
- SDWebImage/Core (= 5.8.4)
- SDWebImage/Core (5.8.4)
- SDWebImageWebPCoder (0.6.1):
- SDWebImage (5.10.4):
- SDWebImage/Core (= 5.10.4)
- SDWebImage/Core (5.10.4)
- SDWebImageWebPCoder (0.8.2):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.7)
- SDWebImage/Core (~> 5.10)
- SocketRocket (0.5.1)
- WeexSDK (0.28.0)
- WXDevtool (0.24.0):
......@@ -81,7 +75,7 @@ PODS:
- GCDWebServer
DEPENDENCIES:
- AFNetworking (= 2.6.3)
- AFNetworking
- DoraemonKit/Core (from `../../`)
- DoraemonKit/WithDatabase (from `../../`)
- DoraemonKit/WithGPS (from `../../`)
......@@ -118,27 +112,27 @@ EXTERNAL SOURCES:
CHECKOUT OPTIONS:
FBRetainCycleDetector:
:commit: 1ff2adee84a6ee94a1ae82526104a188774eb90a
:commit: 32c4afc1fc17553f9b69e4edd82cfa3c73dbb331
:git: https://github.com/facebook/FBRetainCycleDetector.git
YYDebugDatabase:
:commit: 87f4214ab9656b75dd74dfcc042cc3b5067ebab6
:git: https://github.com/y500/YYDebugDatabase.git
SPEC CHECKSUMS:
AFNetworking: cb8d14a848e831097108418f5d49217339d4eb60
CocoaLumberjack: bd155f2dd06c0e0b03f876f7a3ee55693122ec94
AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
CocoaLumberjack: e8955b9d337ac307103b0a34fd141c32f27e53c5
DoraemonKit: 919709427c30af94e265532a879ac41797d296d1
FBRetainCycleDetector: 46daef95c2dfa9be34b53087edf6a8f34e4c749c
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
SDWebImage: cf6922231e95550934da2ada0f20f2becf2ceba9
SDWebImageWebPCoder: d0dac55073088d24b2ac1b191a71a8f8d0adac21
SDWebImage: c666b97e1fa9c64b4909816a903322018f0a9c84
SDWebImageWebPCoder: f56ab499e3ea57dfeb6c3187dce183b10e160db0
SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531
WeexSDK: 78861d2f8b78f67e30580c15a54f5b420456db39
WXDevtool: 95b70c73c06fc3299d65bd53ba4b3e0b0087f3cb
YYDebugDatabase: e684a7f79fca2e3673a23347cefb822f911f3124
PODFILE CHECKSUM: 6c5cced982a83d1a6dbfb6e8501724985d70d130
PODFILE CHECKSUM: a955cdaf3e59b0dc21224f229ea928cf97cc0173
COCOAPODS: 1.10.1
COCOAPODS: 1.8.4
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册