├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── json2java.xml
├── libraries
│ ├── Flutter_Plugins.xml
│ └── Flutter_for_Android.xml
├── runConfigurations
│ └── example_lib_main_dart.xml
└── vcs.xml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── android
├── .gitignore
├── .idea
│ ├── .name
│ ├── caches
│ │ └── build_file_checksums.ser
│ ├── codeStyles
│ │ └── Project.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── modules.xml
│ └── runConfigurations.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── brzhang
│ └── flutter
│ └── dim
│ └── DimPlugin.java
├── dim.iml
├── dim_android.iml
├── example
├── .gitignore
├── .idea
│ ├── libraries
│ │ ├── Dart_SDK.xml
│ │ └── Flutter_for_Android.xml
│ ├── modules.xml
│ ├── runConfigurations
│ │ └── main_dart.xml
│ └── workspace.xml
├── .metadata
├── android
│ ├── .gitignore
│ ├── .idea
│ │ └── codeStyles
│ │ │ └── Project.xml
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── brzhang
│ │ │ │ └── flutter
│ │ │ │ └── dimexample
│ │ │ │ └── MainActivity.java
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── dim_example.iml
├── dim_example_android.iml
├── flutter_01.log
├── flutter_02.log
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── flutter_export_environment.sh
│ ├── Frameworks
│ │ └── libstdc++.6.0.9.dylib
│ ├── Podfile
│ ├── Podfile.lock
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── Runner
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── main.m
├── lib
│ └── main.dart
├── pubspec.yaml
└── test
│ └── widget_test.dart
├── ios
├── .gitignore
├── Assets
│ └── .gitkeep
├── Classes
│ ├── DimModel.h
│ ├── DimModel.m
│ ├── DimPlugin.h
│ ├── DimPlugin.m
│ └── MJExtension
│ │ ├── Info.plist
│ │ ├── MJExtension.h
│ │ ├── MJExtensionConst.h
│ │ ├── MJExtensionConst.m
│ │ ├── MJFoundation.h
│ │ ├── MJFoundation.m
│ │ ├── MJProperty.h
│ │ ├── MJProperty.m
│ │ ├── MJPropertyKey.h
│ │ ├── MJPropertyKey.m
│ │ ├── MJPropertyType.h
│ │ ├── MJPropertyType.m
│ │ ├── NSObject+MJClass.h
│ │ ├── NSObject+MJClass.m
│ │ ├── NSObject+MJCoding.h
│ │ ├── NSObject+MJCoding.m
│ │ ├── NSObject+MJKeyValue.h
│ │ ├── NSObject+MJKeyValue.m
│ │ ├── NSObject+MJProperty.h
│ │ ├── NSObject+MJProperty.m
│ │ ├── NSString+MJExtension.h
│ │ └── NSString+MJExtension.m
└── dim.podspec
├── lib
├── dim.dart
└── manger.dart
└── pubspec.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 | pubspec.lock
7 | .idea/
8 | build/
9 | ios/*.framework
10 | .idea
11 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/json2java.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/libraries/Flutter_Plugins.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/Flutter_for_Android.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/example_lib_main_dart.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.2.7
2 | 消息增加时间戳
3 |
4 | ## 0.2.6
5 | 可以发送语音消息
6 |
7 | ## 0.2.5
8 | 增加新的会话监听
9 |
10 | ## 0.2.4
11 | 简化描述
12 |
13 | ## 0.2.3
14 | 迁移仓库
15 |
16 | ## 0.2.2
17 | 修改一些说明文件。
18 |
19 | ## 0.2.1
20 | 修改不支持的引用头文件的方式。
21 |
22 | ## 0.2.0
23 | 升级imsdk到官方最新版本。
24 |
25 | ## 0.1.19
26 | 获取用户个人资料
27 |
28 | ## 0.1.16
29 | 简化dim的使用,android端不在需要在AndroidManifests.xml文件中配置service等内容,全部交给插件处理。
30 |
31 | ## 0.1.13
32 |
33 | * 归一化错误码
34 |
35 | ## 0.1.11
36 |
37 | * 去掉无用api,解决消息重复的问题,定位到是重复登录注册了多次listener,做了容错处理。
38 |
39 | ## 0.1.8
40 |
41 | * 解决了消息解析不出的问题。
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | TODO: Add your license here.
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dim
2 |
3 | 封装的一个腾讯云im,以便于flutter开发者可以方便继承im到自己的应用中
4 |
5 | ## 使用之前注意事项
6 |
7 | 如果你之前没有使用过腾讯云,请仔细阅读这段文字,如果你已经对腾讯云im了如指掌,可以越过,但建议还是熟悉以下。
8 |
9 | 因为这个库是基于腾讯云im的,因此需要去云im申请一个应用,阅读这篇[文章](https://github.com/tencentyun/TIMSDK/tree/master/Android)可以获得以下知识:
10 |
11 | 1、`appid`怎么来的
12 |
13 | 2、`账号`及其对应的`sig`如何来的,已经推荐的sig的生成方式(当然这个是后台同学关注的)。
14 |
15 | 弄清楚这些之后,就可以开始使用`dim`了。
16 |
17 | ## 使用 dim
18 | dim的使用非常简单,只需引入这个库就可以使用了。
19 |
20 | ```dart
21 | dependencies:
22 | dim: ^0.2.6
23 | ```
24 |
25 | 不需要像我之前实现的版本那样进行一些繁琐的配置,因为云im升级之后,支持`maven`以及`pod`的引用方式啦。那么Android端
26 |
27 |
28 | ### Android端需要注意什么?
29 |
30 | 1、混淆配置,在你的flutter的Android工程中配置混淆。
31 |
32 | ```java
33 | -keep class com.tencent.** { *; }
34 | ```
35 |
36 | ### IOS端需要注意什么?
37 |
38 | 1、请注意在你的flutter工程的ios项目根目录执行`pod update`[**非必须,如果报错建议执行一次**]
39 |
40 | 2、随后在执行一次`pod install`
41 |
42 |
43 | ### demo截图
44 |
45 | 
46 |
47 |
48 | 
49 |
50 |
51 | ## 已有的功能
52 |
53 | 1. 初始化
54 |
55 | 建议整个应用生命周期只执行一次。
56 | 2. 登录
57 | 3. 登出
58 | 4. 获取会话列表
59 | 5. 删除一个会话
60 | 6. 获取私信会话消息[群聊消息目前没有封装]
61 |
62 | 注意,私信发送方的资料云im改成了异步的方式,因此,这个版本不在返回!
63 | 建议用户自己查询一次,最好的方式是将用户资料存储在本地db中,并
64 | 7. 发送图片消息
65 |
66 | 注意,图片消息中图片云im需要的是图片的`本地路径`。
67 | 8. 发送文本消息
68 | 9. 发送地理位置消息
69 | 10. 获取用户资料
70 | 11. 设置用户资料
71 |
72 | 目前仅仅提供了设置`nick`,`gender`,`faceUrl`,有需要在补充。
73 | 12. 监听新的消息
74 | 13. 监听有新的会话
75 |
76 | 注意,和新的消息是一个消息通道,只不过收到的内容是`[]`,对一个空的数组,此时需要去主动调用4获取会话列表来查最新会话列表
77 | 14. 发送语音消息,基本和图片消息一致,使用本地路径
78 |
79 |
80 |
81 | ### 注意
82 |
83 | demo中的 initListener 中的逻辑需要调用一下,最好是在initState中,建立消息通道,flutter这边才能收发消息。
84 |
85 |
86 | ## todo
87 |
88 | 根据需要,可以提issue,或者接受pr来实现更多的接口,主要是体力活。
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/android/.idea/.name:
--------------------------------------------------------------------------------
1 | dim
--------------------------------------------------------------------------------
/android/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/android/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/android/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/android/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
--------------------------------------------------------------------------------
/android/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/android/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | group 'com.brzhang.flutter.dim'
2 | version '1.0-SNAPSHOT'
3 |
4 | buildscript {
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 |
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.1.2'
12 | }
13 | }
14 |
15 | rootProject.allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | }
20 | }
21 |
22 | apply plugin: 'com.android.library'
23 |
24 | android {
25 | compileSdkVersion 27
26 |
27 | defaultConfig {
28 | minSdkVersion 16
29 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
30 | }
31 | lintOptions {
32 | disable 'InvalidPackage'
33 | }
34 | dependencies {
35 | implementation fileTree(include: ['*.jar'], dir: 'libs')
36 | implementation 'com.google.code.gson:gson:2.8.5'
37 | implementation 'com.tencent.imsdk:imsdk:4+'
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | systemProp.http.proxyHost=127.0.0.1
3 | systemProp.http.proxyPort=12759
4 | systemProp.https.proxyHost=127.0.0.1
5 | systemProp.https.proxyPort=12759
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 02 11:29:13 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'dim'
2 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/dim.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/dim_android.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 |
7 | build/
8 |
9 | .flutter-plugins
10 |
--------------------------------------------------------------------------------
/example/.idea/libraries/Dart_SDK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/example/.idea/libraries/Flutter_for_Android.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/example/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/example/.idea/runConfigurations/main_dart.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/example/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/example/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 1cb2677234175e0d7e06742eef6e865a755f07ff
8 | channel: master
9 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.class
3 | .gradle
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | GeneratedPluginRegistrant.java
11 |
--------------------------------------------------------------------------------
/example/android/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | throw new GradleException("versionCode not found. Define flutter.versionCode in the local.properties file.")
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | throw new GradleException("versionName not found. Define flutter.versionName in the local.properties file.")
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 27
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
36 | applicationId "com.brzhang.flutter.dimexample"
37 | minSdkVersion 16
38 | targetSdkVersion 27
39 | versionCode flutterVersionCode.toInteger()
40 | versionName flutterVersionName
41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
42 | }
43 |
44 | buildTypes {
45 | release {
46 | // TODO: Add your own signing config for the release build.
47 | // Signing with the debug keys for now, so `flutter run --release` works.
48 | signingConfig signingConfigs.debug
49 | }
50 | }
51 | }
52 |
53 | flutter {
54 | source '../..'
55 | }
56 |
57 | dependencies {
58 | testImplementation 'junit:junit:4.12'
59 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
61 | }
62 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
9 |
14 |
17 |
24 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/brzhang/flutter/dimexample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.brzhang.flutter.dimexample;
2 |
3 | import android.os.Bundle;
4 | import io.flutter.app.FlutterActivity;
5 | import io.flutter.plugins.GeneratedPluginRegistrant;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | GeneratedPluginRegistrant.registerWith(this);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.1.4'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/example/dim_example.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/example/dim_example_android.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/example/flutter_01.log:
--------------------------------------------------------------------------------
1 | Flutter crash report; please file at https://github.com/flutter/flutter/issues.
2 |
3 | ## command
4 |
5 | flutter doctor
6 |
7 | ## exception
8 |
9 | VersionCheckError: VersionCheckError: Command exited with code 1: git log -n 1 --pretty=format:%ad --date=iso
10 | Standard error: xcrun: error: active developer path ("/Applications/Xcode.app/Contents/Developer") does not exist
11 | Use `sudo xcode-select --switch path/to/Xcode.app` to specify the Xcode that you wish to use for command line developer tools, or use `xcode-select --install` to install the standalone command line developer tools.
12 | See `man xcode-select` for more details.
13 |
14 |
15 | ```
16 | #0 _runSync (package:flutter_tools/src/version.dart:475:5)
17 | #1 FlutterVersion._latestGitCommitDate (package:flutter_tools/src/version.dart:129:12)
18 | #2 FlutterVersion.frameworkCommitDate (package:flutter_tools/src/version.dart:120:37)
19 | #3 FlutterVersion.frameworkDate (package:flutter_tools/src/version.dart:83:31)
20 | #4 _FlutterValidator.validate (package:flutter_tools/src/doctor.dart:286:45)
21 |
22 | #5 Doctor.startValidatorTasks (package:flutter_tools/src/doctor.dart:88:56)
23 | #6 Doctor.diagnose (package:flutter_tools/src/doctor.dart:145:41)
24 |
25 | #7 DoctorCommand.runCommand (package:flutter_tools/src/commands/doctor.dart:29:39)
26 |
27 | #8 FlutterCommand.verifyThenRunCommand (package:flutter_tools/src/runner/flutter_command.dart:347:18)
28 | #9 _asyncThenWrapperHelper. (dart:async/runtime/libasync_patch.dart:77:64)
29 | #10 _rootRunUnary (dart:async/zone.dart:1132:38)
30 | #11 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
31 | #12 _FutureListener.handleValue (dart:async/future_impl.dart:129:18)
32 | #13 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:642:45)
33 | #14 Future._propagateToListeners (dart:async/future_impl.dart:671:32)
34 | #15 Future._complete (dart:async/future_impl.dart:476:7)
35 | #16 _SyncCompleter.complete (dart:async/future_impl.dart:51:12)
36 | #17 _AsyncAwaitCompleter.complete. (dart:async/runtime/libasync_patch.dart:33:20)
37 | #18 _rootRun (dart:async/zone.dart:1124:13)
38 | #19 _CustomZone.run (dart:async/zone.dart:1021:19)
39 | #20 _CustomZone.bindCallback. (dart:async/zone.dart:947:23)
40 | #21 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
41 | #22 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
42 | #23 _runPendingImmediateCallback (dart:isolate/runtime/libisolate_patch.dart:113:13)
43 | #24 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:166:5)
44 | ```
45 |
46 | ## flutter doctor
47 |
48 | ```
49 | encountered exception: VersionCheckError: Command exited with code 1: git log -n 1 --pretty=format:%ad --date=iso
50 | Standard error: xcrun: error: active developer path ("/Applications/Xcode.app/Contents/Developer") does not exist
51 | Use `sudo xcode-select --switch path/to/Xcode.app` to specify the Xcode that you wish to use for command line developer tools, or use `xcode-select --install` to install the standalone command line developer tools.
52 | See `man xcode-select` for more details.
53 |
54 |
55 | #0 _runSync (package:flutter_tools/src/version.dart:475:5)
56 | #1 FlutterVersion._latestGitCommitDate (package:flutter_tools/src/version.dart:129:12)
57 | #2 FlutterVersion.frameworkCommitDate (package:flutter_tools/src/version.dart:120:37)
58 | #3 FlutterVersion.frameworkDate (package:flutter_tools/src/version.dart:83:31)
59 | #4 _FlutterValidator.validate (package:flutter_tools/src/doctor.dart:286:45)
60 |
61 | #5 Doctor.startValidatorTasks (package:flutter_tools/src/doctor.dart:88:56)
62 | #6 Doctor.diagnose (package:flutter_tools/src/doctor.dart:145:41)
63 |
64 | #7 _doctorText. (package:flutter_tools/runner.dart:194:26)
65 | #8 AppContext.run. (package:flutter_tools/src/base/context.dart:142:29)
66 |
67 | #9 _rootRun (dart:async/zone.dart:1124:13)
68 | #10 _CustomZone.run (dart:async/zone.dart:1021:19)
69 | #11 _runZoned (dart:async/zone.dart:1516:10)
70 | #12 runZoned (dart:async/zone.dart:1463:12)
71 | #13 AppContext.run (package:flutter_tools/src/base/context.dart:141:18)
72 |
73 | #14 _doctorText (package:flutter_tools/runner.dart:193:19)
74 |
75 | #15 _createLocalCrashReport (package:flutter_tools/runner.dart:171:32)
76 |
77 | #16 _handleToolError (package:flutter_tools/runner.dart:126:33)
78 |
79 | #17 run. (package:flutter_tools/runner.dart:63:20)
80 |
81 | #18 AppContext.run. (package:flutter_tools/src/base/context.dart:142:29)
82 |
83 | #19 _rootRun (dart:async/zone.dart:1124:13)
84 | #20 _CustomZone.run (dart:async/zone.dart:1021:19)
85 | #21 _runZoned (dart:async/zone.dart:1516:10)
86 | #22 runZoned (dart:async/zone.dart:1463:12)
87 | #23 AppContext.run (package:flutter_tools/src/base/context.dart:141:18)
88 |
89 | #24 runInContext (package:flutter_tools/src/context_runner.dart:42:24)
90 |
91 | #25 run (package:flutter_tools/runner.dart:50:10)
92 | #26 main (package:flutter_tools/executable.dart:51:9)
93 |
94 | #27 main (file:///Users/joshuaton/Documents/Code/Flutter/flutter/packages/flutter_tools/bin/flutter_tools.dart:8:3)
95 | #28 _startIsolate. (dart:isolate/runtime/libisolate_patch.dart:277:32)
96 | #29 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:165:12)
97 | ```
98 |
--------------------------------------------------------------------------------
/example/flutter_02.log:
--------------------------------------------------------------------------------
1 | Flutter crash report; please file at https://github.com/flutter/flutter/issues.
2 |
3 | ## command
4 |
5 | flutter build bundle --suppress-analytics --target lib/main.dart --preview-dart-2 --depfile /Users/hoollyzhang/henCode/dim/example/build/app/intermediates/flutter/debug/snapshot_blob.bin.d --asset-dir /Users/hoollyzhang/henCode/dim/example/build/app/intermediates/flutter/debug/flutter_assets --debug
6 |
7 | ## exception
8 |
9 | ArgumentError: Invalid argument(s): Cannot find executable for /Users/hoollyzhang/flutter/flutter/bin/cache/dart-sdk/bin/pub.
10 |
11 | ```
12 | #0 _getExecutable (package:process/src/interface/local_process_manager.dart:113:5)
13 | #1 LocalProcessManager.start (package:process/src/interface/local_process_manager.dart:41:7)
14 | #2 runCommand (package:flutter_tools/src/base/process.dart:115:25)
15 | #3 runCommandAndStreamOutput (package:flutter_tools/src/base/process.dart:133:33)
16 |
17 | #4 pub (package:flutter_tools/src/dart/pub.dart:155:18)
18 |
19 | #5 pubGet (package:flutter_tools/src/dart/pub.dart:104:13)
20 |
21 | #6 FlutterCommand.verifyThenRunCommand (package:flutter_tools/src/runner/flutter_command.dart:334:13)
22 |
23 | #7 FlutterCommand.run. (package:flutter_tools/src/runner/flutter_command.dart:282:33)
24 |
25 | #8 AppContext.run. (package:flutter_tools/src/base/context.dart:142:29)
26 |
27 | #9 _rootRun (dart:async/zone.dart:1124:13)
28 | #10 _CustomZone.run (dart:async/zone.dart:1021:19)
29 | #11 _runZoned (dart:async/zone.dart:1516:10)
30 | #12 runZoned (dart:async/zone.dart:1463:12)
31 | #13 AppContext.run (package:flutter_tools/src/base/context.dart:141:18)
32 |
33 | #14 FlutterCommand.run (package:flutter_tools/src/runner/flutter_command.dart:273:20)
34 | #15 CommandRunner.runCommand (package:args/command_runner.dart:194:27)
35 |
36 | #16 FlutterCommandRunner.runCommand. (package:flutter_tools/src/runner/flutter_command_runner.dart:346:21)
37 |
38 | #17 AppContext.run. (package:flutter_tools/src/base/context.dart:142:29)
39 |
40 | #18 _rootRun (dart:async/zone.dart:1124:13)
41 | #19 _CustomZone.run (dart:async/zone.dart:1021:19)
42 | #20 _runZoned (dart:async/zone.dart:1516:10)
43 | #21 runZoned (dart:async/zone.dart:1463:12)
44 | #22 AppContext.run (package:flutter_tools/src/base/context.dart:141:18)
45 |
46 | #23 FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:302:19)
47 |
48 | #24 CommandRunner.run. (package:args/command_runner.dart:109:29)
49 | #25 new Future.sync (dart:async/future.dart:224:31)
50 | #26 CommandRunner.run (package:args/command_runner.dart:109:11)
51 | #27 FlutterCommandRunner.run (package:flutter_tools/src/runner/flutter_command_runner.dart:211:18)
52 | #28 run. (package:flutter_tools/runner.dart:59:20)
53 |
54 | #29 AppContext.run. (package:flutter_tools/src/base/context.dart:142:29)
55 |
56 | #30 _rootRun (dart:async/zone.dart:1124:13)
57 | #31 _CustomZone.run (dart:async/zone.dart:1021:19)
58 | #32 _runZoned (dart:async/zone.dart:1516:10)
59 | #33 runZoned (dart:async/zone.dart:1463:12)
60 | #34 AppContext.run (package:flutter_tools/src/base/context.dart:141:18)
61 |
62 | #35 runInContext (package:flutter_tools/src/context_runner.dart:42:24)
63 |
64 | #36 run (package:flutter_tools/runner.dart:50:10)
65 | #37 main (package:flutter_tools/executable.dart:51:9)
66 |
67 | #38 main (file:///Users/hoollyzhang/flutter/flutter/packages/flutter_tools/bin/flutter_tools.dart:8:3)
68 | #39 _startIsolate. (dart:isolate/runtime/libisolate_patch.dart:284:32)
69 | #40 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:169:12)
70 | ```
71 |
72 | ## flutter doctor
73 |
74 | ```
75 | [✓] Flutter (Channel master, v0.5.9-pre.10, on Mac OS X 10.13.5 17F77, locale zh-Hans-CN)
76 | • Flutter version 0.5.9-pre.10 at /Users/hoollyzhang/flutter/flutter
77 | • Framework revision 21f22ed3ba (2 weeks ago), 2018-08-26 19:50:02 -0400
78 | • Engine revision af42b6dc95
79 | • Dart version 2.0.0-dev.69.5.flutter-eab492385c
80 |
81 | [!] Android toolchain - develop for Android devices (Android SDK 28.0.0)
82 | • Android SDK at /Users/hoollyzhang/Library/Android/sdk
83 | • Android NDK at /Users/hoollyzhang/Library/Android/sdk/ndk-bundle
84 | • Platform android-28, build-tools 28.0.0
85 | • ANDROID_HOME = /Users/hoollyzhang/Library/Android/sdk
86 | • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
87 | • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)
88 | ✗ Android license status unknown.
89 |
90 | [✓] iOS toolchain - develop for iOS devices (Xcode 9.4.1)
91 | • Xcode at /Applications/Xcode.app/Contents/Developer
92 | • Xcode 9.4.1, Build version 9F2000
93 | • ios-deploy 1.9.2
94 | • CocoaPods version 1.5.3
95 |
96 | [✓] Android Studio (version 3.1)
97 | • Android Studio at /Applications/Android Studio.app/Contents
98 | • Flutter plugin version 26.0.1
99 | • Dart plugin version 173.4700
100 | • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1024-b01)
101 |
102 | [!] IntelliJ IDEA Ultimate Edition (version 2017.3.4)
103 | • IntelliJ at /Applications/IntelliJ IDEA.app
104 | ✗ Flutter plugin not installed; this adds Flutter specific functionality.
105 | ✗ Dart plugin not installed; this adds Dart specific functionality.
106 | • For information about installing plugins, see
107 | https://flutter.io/intellij-setup/#installing-the-plugins
108 |
109 | [!] VS Code (version 1.23.1)
110 | • VS Code at /Applications/Visual Studio Code.app/Contents
111 | • Flutter extension not installed; install from
112 | https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter
113 |
114 | [✓] Connected devices (2 available)
115 | • HUAWEI NXT AL10 • 5LM7N16401002621 • android-arm64 • Android 7.0 (API 24)
116 | • 张勇的 iPhone • c50a3c88e239175b7a126ab35c4ada3a86395abb • ios • iOS 11.4.1
117 |
118 | ! Doctor found issues in 3 categories.
119 | ```
120 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .sconsign.dblite
4 | .svn/
5 |
6 | .DS_Store
7 | *.swp
8 | profile
9 |
10 | DerivedData/
11 | build/
12 | GeneratedPluginRegistrant.h
13 | GeneratedPluginRegistrant.m
14 |
15 | .generated/
16 |
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 |
22 | !default.pbxuser
23 | !default.mode1v3
24 | !default.mode2v3
25 | !default.perspectivev3
26 |
27 | xcuserdata
28 |
29 | *.moved-aside
30 |
31 | *.pyc
32 | *sync/
33 | Icon?
34 | .tags*
35 |
36 | /Flutter/app.flx
37 | /Flutter/app.zip
38 | /Flutter/flutter_assets/
39 | /Flutter/App.framework
40 | /Flutter/Flutter.framework
41 | /Flutter/Generated.xcconfig
42 | /ServiceDefinitions.json
43 |
44 | Pods/
45 | .symlinks/
46 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/flutter_export_environment.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a generated file; do not edit or check into version control.
3 | export "FLUTTER_ROOT=/Users/hoollyzhang/flutter/flutter"
4 | export "FLUTTER_APPLICATION_PATH=/Users/hoollyzhang/henCode/dim/example"
5 | export "FLUTTER_TARGET=/Users/hoollyzhang/henCode/dim/example/lib/main.dart"
6 | export "FLUTTER_BUILD_DIR=build"
7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios"
8 | export "FLUTTER_FRAMEWORK_DIR=/Users/hoollyzhang/flutter/flutter/bin/cache/artifacts/engine/ios"
9 | export "FLUTTER_BUILD_NAME=1.0.0"
10 | export "FLUTTER_BUILD_NUMBER=1"
11 | export "TRACK_WIDGET_CREATION=true"
12 |
--------------------------------------------------------------------------------
/example/ios/Frameworks/libstdc++.6.0.9.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Frameworks/libstdc++.6.0.9.dylib
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def parse_KV_file(file, separator='=')
14 | file_abs_path = File.expand_path(file)
15 | if !File.exists? file_abs_path
16 | return [];
17 | end
18 | pods_ary = []
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) { |line|
21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22 | plugin = line.split(pattern=separator)
23 | if plugin.length == 2
24 | podname = plugin[0].strip()
25 | path = plugin[1].strip()
26 | podpath = File.expand_path("#{path}", file_abs_path)
27 | pods_ary.push({:name => podname, :path => podpath});
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | }
32 | return pods_ary
33 | end
34 |
35 | target 'Runner' do
36 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
37 | # referring to absolute paths on developers' machines.
38 | system('rm -rf .symlinks')
39 | system('mkdir -p .symlinks/plugins')
40 |
41 | # Flutter Pods
42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
43 | if generated_xcode_build_settings.empty?
44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
45 | end
46 | generated_xcode_build_settings.map { |p|
47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
48 | symlink = File.join('.symlinks', 'flutter')
49 | File.symlink(File.dirname(p[:path]), symlink)
50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
51 | end
52 | }
53 |
54 | # Plugin Pods
55 | plugin_pods = parse_KV_file('../.flutter-plugins')
56 | plugin_pods.map { |p|
57 | symlink = File.join('.symlinks', 'plugins', p[:name])
58 | File.symlink(p[:path], symlink)
59 | pod p[:name], :path => File.join(symlink, 'ios')
60 | }
61 | end
62 |
63 | post_install do |installer|
64 | installer.pods_project.targets.each do |target|
65 | target.build_configurations.each do |config|
66 | config.build_settings['ENABLE_BITCODE'] = 'NO'
67 | end
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/example/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - dim (0.2.6):
3 | - Flutter
4 | - TXIMSDK_iOS
5 | - YYModel
6 | - Flutter (1.0.0)
7 | - TXIMSDK_iOS (4.3.135)
8 | - YYModel (1.0.4)
9 |
10 | DEPENDENCIES:
11 | - dim (from `.symlinks/plugins/dim/ios`)
12 | - Flutter (from `.symlinks/flutter/ios`)
13 |
14 | SPEC REPOS:
15 | https://github.com/cocoapods/specs.git:
16 | - TXIMSDK_iOS
17 | - YYModel
18 |
19 | EXTERNAL SOURCES:
20 | dim:
21 | :path: ".symlinks/plugins/dim/ios"
22 | Flutter:
23 | :path: ".symlinks/flutter/ios"
24 |
25 | SPEC CHECKSUMS:
26 | dim: 51ecffa284a3f408c576059f4a15eb23214841b0
27 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
28 | TXIMSDK_iOS: 46fd4c57411f140559d0222423cef27776722684
29 | YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
30 |
31 | PODFILE CHECKSUM: fbaee5b23138ad4cd0cb935c94fcf473f272085c
32 |
33 | COCOAPODS: 1.7.5
34 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildSystemType
6 | Original
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 |
10 | // Override point for customization after application launch.
11 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
12 | }
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | dim_example
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/example/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:async';
3 |
4 | import 'package:flutter/services.dart';
5 | import 'package:dim/dim.dart';
6 |
7 | import 'dart:math';
8 |
9 | void main() => runApp(new MyApp());
10 |
11 | class MyApp extends StatefulWidget {
12 | @override
13 | _MyAppState createState() => new _MyAppState();
14 | }
15 |
16 | class _MyAppState extends State {
17 | Dim _dim = new Dim();
18 |
19 | String _result = "";
20 |
21 | List _users = List();
22 |
23 | //在另外一个手机上测试改变下用户,靠这里了
24 | int _currentUser = 0;
25 |
26 | int appid = 1400215656;
27 |
28 | StreamSubscription _messageStreamSubscription;
29 |
30 | @override
31 | void initState() {
32 | super.initState();
33 | ////大家 一个消息监听通道要记得在initState中调用一下哦。
34 | initListener();
35 | _users.add({
36 | 'username': 'hoolly1',
37 | 'sig':
38 | "eJxlj8FPgzAche-8FYTrjLbQgngbbkEmHIgzZF4Iwg*obLTSssmM-7sRNTbxXb8v7*W9G6ZpWtv44bIoSz72KleTAMu8MS1kXfxBIViVFyp3huofhDfBBsiLWsEwQ0wptRHSHVZBr1jNfoyW8-1*wpogqy6fV74bCEI2pi51dYU1M0zWu9soXWUp37Q0CKYoCGJVPi3ASRkbty*CyCQeC7dZc1igFK5OUbvchMdyyvz7tqulF3qrJT3Is-vYvI4nz92hwc-EHQnpM0k6bVKxA-xe8sk19oij0SMMkvF*FmyEKbYd9BXL*DA*AfzTXb0_"
39 | });
40 | _users.add({
41 | 'username': 'hoolly2',
42 | 'sig':
43 | "eJxlj8FOg0AURfd8BWFbIzMDM60mLhqUhNpqacUFGwKdgb4yDATGltb470bUSOLbnpN773s3TNO0Xpbb63S3q9*UTvS5EZZ5a1rIuvqDTQM8SXXitPwfFH0DrUjSXIt2gJhSShAaO8CF0pDDj7GvaynPZCR0vEyGlu8EFyGCKaNsrEAxwNVD5AXhPeHk4D1uTq7wudL9pVB9PJmjCmTZ*pn0Q8*3N9sc8qciKBbsGOBYnEo2E5nM9yxmr5FcVwd7MWEdrHHozLPnVbS0w7tRpYZK-L50487wdDrefBRtB7UaBIIwxcRBX2cZH8YnH3NdyQ__"
44 | });
45 | _users.add({
46 | 'username': 'hoolly3',
47 | 'sig':
48 | "eJxlj11PgzAARd-5FU2fjbZA2ccbwW0QYbqMEeSlAdpB2YQGyiYx-ncjakbifT0n9*Z*aAAAGPr7*zTPm75WVA2SQ7AEEMG7G5RSMJoqarTsH*TvUrScpkfF2xFiQoiO0NQRjNdKHMWvUTbN*TwYE6FjJzqu-DSYCOmYWMSaKqIYYbB6dbyd40XeY6i8uHpyS5*blzBKtv1zvtrGa9Zd1yeLWb0hrzxyba*0g83eVpsgr5wC6Vl8KHYvWZUmTvdQJ2o4ZHXH0eD77tywJ5NKvPG-SwtzjmeL2YReeNuJph4FHWGCdQN9B2qf2hc3HF5a"
49 | });
50 | }
51 |
52 | // Platform messages are asynchronous, so we initialize in an async method.
53 | Future initListener() async {
54 | // message was in flight, we want to discard the reply rather than calling
55 | // setState to update our non-existent appearance.
56 | if (!mounted) return;
57 |
58 | if (_messageStreamSubscription == null) {
59 | _messageStreamSubscription = _dim.onMessage.listen((dynamic onData) {
60 | print(
61 | "我监听到数据了$onData,需要在这里判断是你是消息列表还是需要刷新会话的请求。会话的请求是一个空的列表[],消息列表是有内容的");
62 | });
63 | }
64 | }
65 |
66 | @override
67 | void dispose() {
68 | // TODO: implement dispose
69 | super.dispose();
70 | //flutter 这里应该页面退出栈会调用,但是如果这个是根页面,日志是打不出来的。
71 | canCelListener();
72 | }
73 |
74 | @override
75 | Widget build(BuildContext context) {
76 | return new MaterialApp(
77 | home: new Scaffold(
78 | appBar: new AppBar(
79 | title: Text('当前账号' + _users[_currentUser]["username"]),
80 | ),
81 | body: new Center(
82 | child: CustomScrollView(
83 | primary: false,
84 | slivers: [
85 | SliverPersistentHeader(
86 | delegate: _SliverAppBarDelegate(
87 | minHeight: 30,
88 | maxHeight: 200,
89 | child: Container(
90 | margin: EdgeInsets.all(10),
91 | padding: EdgeInsets.all(4),
92 | decoration: BoxDecoration(
93 | border: Border.all(),
94 | borderRadius: BorderRadius.all(Radius.circular(5))),
95 | child: SingleChildScrollView(
96 | child: Text(_result.isEmpty ? "这里显示输出结果" : _result),
97 | ),
98 | )),
99 | pinned: true,
100 | ),
101 | SliverPadding(
102 | padding: const EdgeInsets.all(10.0),
103 | sliver: SliverGrid.count(
104 | crossAxisSpacing: 10.0,
105 | mainAxisSpacing: 10.0,
106 | crossAxisCount: 4,
107 | children: [
108 | RaisedButton(
109 | onPressed: () {
110 | init();
111 | },
112 | child: Text('初始化'),
113 | ),
114 | RaisedButton(
115 | onPressed: () {
116 | login();
117 | },
118 | child: Text('登录'),
119 | ),
120 | RaisedButton(
121 | onPressed: () {
122 | logout();
123 | },
124 | child: Text('登出'),
125 | ),
126 | RaisedButton(
127 | onPressed: () {
128 | postData();
129 | },
130 | child: Text('测试发送数据'),
131 | ),
132 | // RaisedButton(
133 | // onPressed: () {
134 | // canCelListener();
135 | // },
136 | // child: Text('取消监听'),
137 | // ),
138 | RaisedButton(
139 | onPressed: () {
140 | sendTextMsg();
141 | },
142 | child: Text('发文本'),
143 | ),
144 | RaisedButton(
145 | onPressed: () {
146 | sendImageMsg();
147 | },
148 | child: Text('发图片'),
149 | ),
150 | RaisedButton(
151 | onPressed: () {
152 | sendLocationMsg();
153 | },
154 | child: Text('发位置'),
155 | ),
156 | RaisedButton(
157 | onPressed: () {
158 | getMessages();
159 | },
160 | padding: EdgeInsets.all(0),
161 | child: Text('历史消息'),
162 | ),
163 | RaisedButton(
164 | onPressed: () {
165 | getUserInfo();
166 | },
167 | child: Text('拿资料'),
168 | ),
169 | RaisedButton(
170 | padding: EdgeInsets.all(0),
171 | onPressed: () {
172 | setUserInfo();
173 | },
174 | child: Text('设置资料'),
175 | ),
176 | RaisedButton(
177 | padding: EdgeInsets.all(0),
178 | onPressed: () {
179 | getConversations();
180 | },
181 | child: Text('会话列表'),
182 | ),
183 | ],
184 | ),
185 | ),
186 | ],
187 | ),
188 | ),
189 | ),
190 | );
191 | }
192 |
193 | Future postData() async {
194 | try {
195 | var result = await _dim.postDataTest();
196 | setState(() {
197 | this._result = result;
198 | });
199 | print(result);
200 | } on PlatformException {
201 | print("listen 失败");
202 | }
203 | }
204 |
205 | Future sendTextMsg() async {
206 | try {
207 | var result = await _dim.sendTextMessages(
208 | _users[_users.length - _currentUser - 1]['username'], "haahah");
209 | print(result);
210 | setState(() {
211 | this._result = result;
212 | });
213 | } on PlatformException {
214 | print("发送消息失败");
215 | setState(() {
216 | this._result = "发送消息失败";
217 | });
218 | }
219 | }
220 |
221 | Future sendImageMsg() async {
222 | try {
223 | var result = await _dim.sendImageMessages(
224 | _users[_users.length - _currentUser - 1]['username'],
225 | "tyyhuiijkoi.png");
226 | print(result);
227 | setState(() {
228 | this._result = result;
229 | });
230 | } on PlatformException {
231 | print("发送图片消息失败");
232 | setState(() {
233 | this._result = "发送图片消息失败";
234 | });
235 | }
236 | }
237 |
238 | Future sendLocationMsg() async {
239 | try {
240 | var result = await _dim.sendLocationMessages(
241 | _users[_users.length - _currentUser - 1]['username'],
242 | 113.93,
243 | 22.54,
244 | "腾讯大厦");
245 | print(result);
246 | setState(() {
247 | this._result = result;
248 | });
249 | } on PlatformException {
250 | print("发送位置消息失败");
251 | setState(() {
252 | this._result = "发送位置消息失败";
253 | });
254 | }
255 | }
256 |
257 | ///测试化测试,这里传自己应用的appid
258 | Future init() async {
259 | try {
260 | var result = await _dim.init(appid);
261 | print(result);
262 | setState(() {
263 | this._result = result;
264 | });
265 | } on PlatformException {
266 | print("初始化失败");
267 | }
268 | }
269 |
270 | ///第一个测试账号
271 | Future login() async {
272 | try {
273 | var result = await _dim.imLogin(
274 | _users[_currentUser]['username'], _users[_currentUser]['sig']);
275 | print(result);
276 | setState(() {
277 | this._result = result;
278 | });
279 | } on PlatformException {
280 | print("登录 失败");
281 | }
282 | }
283 |
284 | Future logout() async {
285 | try {
286 | var result = await _dim.imLogout();
287 | print(result);
288 | setState(() {
289 | this._result = result;
290 | });
291 | } on PlatformException {
292 | print("登出 失败");
293 | }
294 | }
295 |
296 | Future getMessages() async {
297 | try {
298 | var result = await _dim.getMessages(
299 | _users[_users.length - _currentUser - 1]['username'],
300 | );
301 | print(result);
302 | setState(() {
303 | this._result = result;
304 | });
305 | } on PlatformException {}
306 | }
307 |
308 | void canCelListener() {
309 | if (_messageStreamSubscription != null) {
310 | _messageStreamSubscription.cancel();
311 | }
312 | }
313 |
314 | void getUserInfo() async {
315 | try {
316 | List users = List();
317 | users.add(_users[_users.length - _currentUser - 1]['username']);
318 | var result = await _dim.getUsersProfile(users);
319 | print(result);
320 | setState(() {
321 | this._result = result;
322 | });
323 | } on PlatformException {
324 | print("获取个人资料失败");
325 | }
326 | }
327 |
328 | void setUserInfo() async {
329 | try {
330 | var result = await _dim.setUsersProfile(
331 | 1, "hz", "https://www.brzhang.club/images/hz.png");
332 | print(result);
333 | setState(() {
334 | this._result = result;
335 | });
336 | } on PlatformException {
337 | print("获取个人资料失败");
338 | }
339 | }
340 |
341 | void getConversations() async {
342 | try {
343 | var result = await _dim.getConversations();
344 | print(result);
345 | setState(() {
346 | this._result = result;
347 | });
348 | } on PlatformException {
349 | print("获取会话列表失败");
350 | }
351 | }
352 | }
353 |
354 | class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
355 | _SliverAppBarDelegate({
356 | @required this.minHeight,
357 | @required this.maxHeight,
358 | @required this.child,
359 | });
360 |
361 | final double minHeight;
362 | final double maxHeight;
363 | final Widget child;
364 |
365 | @override
366 | double get minExtent => minHeight;
367 |
368 | @override
369 | double get maxExtent => max(maxHeight, minHeight);
370 |
371 | @override
372 | Widget build(
373 | BuildContext context, double shrinkOffset, bool overlapsContent) {
374 | return new SizedBox.expand(child: child);
375 | }
376 |
377 | @override
378 | bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
379 | return maxHeight != oldDelegate.maxHeight ||
380 | minHeight != oldDelegate.minHeight ||
381 | child != oldDelegate.child;
382 | }
383 | }
384 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: dim_example
2 | description: Demonstrates how to use the dim plugin.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # Read more about versioning at semver.org.
10 | version: 1.0.0+1
11 |
12 | dependencies:
13 | flutter:
14 | sdk: flutter
15 |
16 | # The following adds the Cupertino Icons font to your application.
17 | # Use with the CupertinoIcons class for iOS style icons.
18 | cupertino_icons: ^0.1.2
19 |
20 | dev_dependencies:
21 | flutter_test:
22 | sdk: flutter
23 |
24 | dim:
25 | path: ../
26 |
27 | # For information on the generic Dart part of this file, see the
28 | # following page: https://www.dartlang.org/tools/pub/pubspec
29 |
30 | # The following section is specific to Flutter.
31 | flutter:
32 |
33 | # The following line ensures that the Material Icons font is
34 | # included with your application, so that you can use the icons in
35 | # the material Icons class.
36 | uses-material-design: true
37 |
38 | # To add assets to your application, add an assets section, like this:
39 | # assets:
40 | # - images/a_dot_burr.jpeg
41 | # - images/a_dot_ham.jpeg
42 |
43 | # An image asset can refer to one or more resolution-specific "variants", see
44 | # https://flutter.io/assets-and-images/#resolution-aware.
45 |
46 | # For details regarding adding assets from package dependencies, see
47 | # https://flutter.io/assets-and-images/#from-packages
48 |
49 | # To add custom fonts to your application, add a fonts section here,
50 | # in this "flutter" section. Each entry in this list should have a
51 | # "family" key with the font family name, and a "fonts" key with a
52 | # list giving the asset and other descriptors for the font. For
53 | # example:
54 | # fonts:
55 | # - family: Schyler
56 | # fonts:
57 | # - asset: fonts/Schyler-Regular.ttf
58 | # - asset: fonts/Schyler-Italic.ttf
59 | # style: italic
60 | # - family: Trajan Pro
61 | # fonts:
62 | # - asset: fonts/TrajanPro.ttf
63 | # - asset: fonts/TrajanPro_Bold.ttf
64 | # weight: 700
65 | #
66 | # For details regarding fonts from package dependencies,
67 | # see https://flutter.io/custom-fonts/#from-packages
68 |
--------------------------------------------------------------------------------
/example/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | // To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter
3 | // provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to
4 | // find child widgets in the widget tree, read text, and verify that the values of widget properties
5 | // are correct.
6 |
7 | //import 'package:flutter/material.dart';
8 | //import 'package:flutter_test/flutter_test.dart';
9 | //
10 | //import 'package:dim_example/main.dart';
11 | //
12 | //void main() {
13 | // testWidgets('Verify Platform version', (WidgetTester tester) async {
14 | // // Build our app and trigger a frame.
15 | // await tester.pumpWidget(new MyApp());
16 | //
17 | // // Verify that platform version is retrieved.
18 | // expect(
19 | // find.byWidgetPredicate(
20 | // (Widget widget) =>
21 | // widget is Text && widget.data.startsWith('Running on:'),
22 | // ),
23 | // findsOneWidget);
24 | // });
25 | //}
26 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .sconsign.dblite
4 | .svn/
5 |
6 | .DS_Store
7 | *.swp
8 | profile
9 |
10 | DerivedData/
11 | build/
12 | GeneratedPluginRegistrant.h
13 | GeneratedPluginRegistrant.m
14 |
15 | .generated/
16 |
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 |
22 | !default.pbxuser
23 | !default.mode1v3
24 | !default.mode2v3
25 | !default.perspectivev3
26 |
27 | xcuserdata
28 |
29 | *.moved-aside
30 |
31 | *.pyc
32 | *sync/
33 | Icon?
34 | .tags*
35 |
36 | /Flutter/Generated.xcconfig
37 |
--------------------------------------------------------------------------------
/ios/Assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bravekingzhang/dim/decc1a81a8e65aa955ff4013b0ae206405e10e27/ios/Assets/.gitkeep
--------------------------------------------------------------------------------
/ios/Classes/DimModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // DimModel.h
3 | // dim
4 | //
5 | // Created by 飞鱼 on 2019/2/15.
6 | //
7 |
8 | #import
9 | #import
10 | NS_ASSUME_NONNULL_BEGIN
11 | //@class TIMUserProfile, TIMConversation, TIMMessage, TIMGroupMemberInfo, TIMElem;
12 |
13 |
14 | @interface DimUser : NSObject
15 | @property (nonatomic, copy) NSString *identifier;
16 | @property (nonatomic, copy) NSString *nickName;
17 | @property (nonatomic, copy) NSString *remark;
18 | @property (nonatomic, copy) NSString *faceURL;
19 | @property (nonatomic, copy) NSString *selfSignature;
20 | @property (nonatomic, assign) NSInteger gender;
21 | @property (nonatomic, assign) NSInteger birthday;
22 | @property (nonatomic, copy) NSString *location;
23 |
24 | + (DimUser *)initWithTimUser:(TIMUserProfile *)timUserProfile;
25 |
26 | @end
27 |
28 | @interface DimConversation : NSObject
29 | @property(nonatomic,assign) TIMConversationType type;
30 | @property (nonatomic, copy) NSString *peer;
31 |
32 | + (DimConversation *)initWithTIMConversation:(TIMConversation *)timConversation;
33 | @end
34 |
35 | @interface DimMessage : NSObject
36 | @property (nonatomic, strong) DimUser *senderProfile;
37 | @property (nonatomic, copy) NSString *sender;
38 | @property (nonatomic, strong) DimConversation *timConversation;
39 | @property (nonatomic, strong) TIMGroupMemberInfo *timGroupMemberInfo;
40 | @property (nonatomic, strong) TIMElem *message;
41 | @property (nonatomic, assign) NSTimeInterval timeStamp;
42 |
43 | + (DimMessage *)initWithTIMMessage:(TIMMessage *)timMessage;
44 | @end
45 |
46 | NS_ASSUME_NONNULL_END
47 |
--------------------------------------------------------------------------------
/ios/Classes/DimModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // DimModel.m
3 | // dim
4 | //
5 | // Created by 飞鱼 on 2019/2/15.
6 | //
7 |
8 | #import "DimModel.h"
9 |
10 | @implementation DimUser
11 |
12 | + (DimUser *)initWithTimUser:(TIMUserProfile *)timUserProfile {
13 | DimUser *dimUser = [[DimUser alloc]init];
14 | dimUser.identifier = timUserProfile.identifier;
15 | dimUser.nickName = timUserProfile.nickname;
16 | dimUser.faceURL = timUserProfile.faceURL;
17 | dimUser.selfSignature = [[NSString alloc]initWithData:timUserProfile.selfSignature encoding:NSUTF8StringEncoding];
18 | dimUser.gender = timUserProfile.gender ? timUserProfile.gender : 1;
19 | dimUser.birthday = timUserProfile.birthday;
20 | dimUser.location = [[NSString alloc]initWithData:timUserProfile.location encoding:NSUTF8StringEncoding];
21 | return dimUser;
22 | }
23 |
24 | @end
25 |
26 | @implementation DimConversation
27 |
28 | + (DimConversation *)initWithTIMConversation:(TIMConversation *)timConversation {
29 | DimConversation *dimConversation = [[DimConversation alloc]init];
30 | dimConversation.type = timConversation.getType;
31 | dimConversation.peer = timConversation.getReceiver;
32 | return dimConversation;
33 | }
34 | @end
35 |
36 | @implementation DimMessage
37 |
38 | + (DimMessage *)initWithTIMMessage:(TIMMessage *)timMessage {
39 | DimMessage *dimMessage = [[DimMessage alloc]init];
40 | dimMessage.sender = timMessage.sender;
41 | dimMessage.timConversation = [DimConversation initWithTIMConversation:timMessage.getConversation];
42 | dimMessage.timGroupMemberInfo = timMessage.getSenderGroupMemberProfile;
43 | dimMessage.message = [timMessage getElem:0];
44 | dimMessage.timeStamp = timMessage.timestamp.timeIntervalSince1970;
45 |
46 | return dimMessage;
47 | }
48 | @end
49 |
--------------------------------------------------------------------------------
/ios/Classes/DimPlugin.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface DimPlugin : NSObject
4 |
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/ios/Classes/DimPlugin.m:
--------------------------------------------------------------------------------
1 | #import "DimPlugin.h"
2 | #import
3 | #import "YYModel.h"
4 | #import "DimModel.h"
5 | #import "MJExtension.h"
6 |
7 | @interface DimPlugin()
8 | @property (nonatomic, strong) FlutterEventSink eventSink;
9 |
10 | @end
11 |
12 | @implementation DimPlugin
13 | + (void)registerWithRegistrar:(NSObject*)registrar {
14 | FlutterMethodChannel *channel = [FlutterMethodChannel
15 | methodChannelWithName:@"dim_method"
16 | binaryMessenger:[registrar messenger]];
17 | DimPlugin* instance = [[DimPlugin alloc] init];
18 | [registrar addMethodCallDelegate:instance channel:channel];
19 |
20 | FlutterEventChannel *eventChannel = [FlutterEventChannel eventChannelWithName:@"dim_event" binaryMessenger:[registrar messenger]];
21 | [eventChannel setStreamHandler:instance];
22 | }
23 |
24 | - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
25 |
26 | if ([@"getPlatformVersion" isEqualToString:call.method]) {
27 | result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
28 | }else if([ @"init" isEqualToString:call.method] ){
29 | int appidInt = [call.arguments[@"appid"] intValue];
30 | //初始化 SDK 基本配置
31 | TIMSdkConfig *config = [[TIMSdkConfig alloc] init];
32 | config.sdkAppId = appidInt;
33 | config.connListener = self;
34 |
35 | //初始化 SDK
36 | int code = [[TIMManager sharedInstance] initSdk:config];
37 | NSLog(@"initSdk:result is %d", code);
38 | //将用户配置与通讯管理器进行绑定
39 | TIMUserConfig *userConfig = [[TIMUserConfig alloc] init];
40 | userConfig.userStatusListener = self;
41 | userConfig.refreshListener = self;
42 | [[TIMManager sharedInstance] setUserConfig:userConfig];
43 | [[TIMManager sharedInstance] removeMessageListener:self];
44 | [[TIMManager sharedInstance] addMessageListener:self];
45 | result(@"init Succ");
46 | } else if ([ @"im_logout" isEqualToString:call.method] ){
47 | [[TIMManager sharedInstance] logout:^{
48 | result(@"Logout Succ");
49 | } fail:^(int code, NSString *msg) {
50 | result([NSString stringWithFormat:@"Login Failed: %d->%@", code, msg]);
51 | }];
52 | }else if([@"im_login" isEqualToString:call.method]) {
53 |
54 | NSString *identifier = call.arguments[@"identifier"];
55 | NSString *userSig = call.arguments[@"userSig"];
56 | NSLog(@"identifier-->userSig:%@-->%@", identifier,userSig);
57 | TIMLoginParam *param = [[TIMLoginParam alloc ]init];
58 |
59 | param.identifier = identifier;
60 | param.userSig = userSig;
61 |
62 | [[TIMManager sharedInstance] login: param succ:^(){
63 | result(@"Login Succ");
64 | } fail:^(int code, NSString * err) {
65 | NSLog(@"Login Failed: %d->%@", code, err);
66 | result([NSString stringWithFormat:@"Login Failed: %d->%@", code, err]);
67 | }];
68 | }else if([@"sdkLogout" isEqualToString:call.method]){
69 | [[TIMManager sharedInstance] logout:^{
70 | result(@"logout success");
71 | } fail:^(int code, NSString *msg) {
72 | [NSString stringWithFormat:@"logout failed. code %d desc %@", code, msg];
73 | }];
74 | }else if([@"getConversations" isEqualToString:call.method]){
75 |
76 | NSArray *conversationList = [[TIMManager sharedInstance] getConversationList];
77 | if (conversationList!=nil && conversationList.count>0) {
78 | NSMutableArray *dictArray = [[NSMutableArray alloc]init];
79 | for (TIMConversation *conversation in conversationList) {
80 | DimConversation *dimConversation = [DimConversation initWithTIMConversation:conversation ];
81 | [dictArray addObject:dimConversation];
82 | }
83 | NSString *jsonString = [dictArray yy_modelToJSONString];
84 | result(jsonString);
85 | }else{
86 | result(@"[]");
87 | }
88 | }else if([@"delConversation" isEqualToString:call.method]){
89 | NSString *identifier = call.arguments[@"identifier"];
90 | [[TIMManager sharedInstance] deleteConversation:TIM_C2C receiver:identifier];
91 | result(@"delConversation success");
92 | }else if([@"getMessages" isEqualToString:call.method]){
93 | NSString *identifier = call.arguments[@"identifier"];
94 | int count = [call.arguments[@"count"] intValue];
95 | int ctype = [call.arguments[@"ctype"] intValue];
96 | //TIMMessage *lastMsg = call.arguments[@"lastMsg"];
97 | TIMConversation *con = [[TIMManager sharedInstance] getConversation: ctype==2 ? TIM_GROUP:TIM_C2C receiver:identifier];
98 | [con getMessage:count last:NULL succ:^(NSArray *msgs) {
99 | if(msgs != nil && msgs.count > 0){
100 | NSMutableArray *dictArray = [[NSMutableArray alloc]init];
101 | for (TIMMessage *message in msgs) {
102 | DimMessage *dimMessage = [DimMessage initWithTIMMessage:message];
103 | [dictArray addObject:dimMessage];
104 | }
105 | NSString *jsonString = [dictArray yy_modelToJSONString];
106 | result(jsonString);
107 | }else{
108 | result(@"[]");
109 | }
110 | } fail:^(int code, NSString *msg) {
111 | result([NSString stringWithFormat:@"get message failed. code: %d msg: %@", code, msg]);
112 | }];
113 | }else if([@"sendTextMessages" isEqualToString:call.method]){
114 | NSString *identifier = call.arguments[@"identifier"];
115 | NSString *content = call.arguments[@"content"];
116 | TIMMessage *msg = [TIMMessage new];
117 |
118 | //添加文本内容
119 | TIMTextElem *elem = [TIMTextElem new];
120 | elem.text = content;
121 |
122 | //将elem添加到消息
123 | if([msg addElem:elem] != 0){
124 | NSLog(@"addElement failed");
125 | return;
126 | }
127 | TIMConversation *conversation = [[TIMManager sharedInstance] getConversation:TIM_C2C receiver:identifier];
128 | //发送消息
129 | [conversation sendMessage:msg succ:^{
130 | result(@"send message ok");
131 | } fail:^(int code, NSString *msg) {
132 | result([NSString stringWithFormat:@"send message failed. code: %d desc:%@", code, msg]);
133 | }];
134 | }else if([@"sendImageMessages" isEqualToString:call.method]){
135 | NSString *identifier = call.arguments[@"identifier"];
136 | NSString *iamgePath = call.arguments[@"image_path"];
137 | //构造一条消息
138 | TIMMessage *msg = [TIMMessage new];
139 |
140 | //添加图片
141 | TIMImageElem *elem = [TIMImageElem new];
142 | elem.path = iamgePath;
143 | if([msg addElem:elem] != 0){
144 | NSLog(@"addElement failed");
145 | }
146 |
147 | TIMConversation *conversation = [[TIMManager sharedInstance] getConversation:TIM_C2C receiver:identifier];
148 | [conversation sendMessage:msg succ:^{
149 | result(@"SendMsg ok");
150 | } fail:^(int code, NSString *msg) {
151 | result([NSString stringWithFormat:@"send message failed. code: %d desc:%@", code, msg]);
152 | }];
153 |
154 | }else if([@"sendSoundMessages" isEqualToString:call.method]){
155 | NSString *identifier = call.arguments[@"identifier"];
156 | NSString *soundpath = call.arguments[@"sound_path"];
157 | int duration = [call.arguments[@"duration"] intValue];
158 | //构造一条消息
159 | TIMMessage *msg = [TIMMessage new];
160 |
161 | //添加声音
162 | TIMSoundElem *elem = [TIMSoundElem new];
163 | elem.path = soundpath;
164 | elem.second = duration;
165 | if([msg addElem:elem] != 0){
166 | NSLog(@"addElement failed");
167 | }
168 |
169 | TIMConversation *conversation = [[TIMManager sharedInstance] getConversation:TIM_C2C receiver:identifier];
170 | [conversation sendMessage:msg succ:^{
171 | result(@"SendMsg ok");
172 | } fail:^(int code, NSString *msg) {
173 | result([NSString stringWithFormat:@"send message failed. code: %d desc:%@", code, msg]);
174 | }];
175 |
176 | }else if([@"sendLocation" isEqualToString:call.method]){
177 | NSString *identifier = call.arguments[@"identifier"];
178 | double lat = [call.arguments[@"lat"] doubleValue];
179 | double lng = [call.arguments[@"lng"] doubleValue];
180 | NSString *desc = call.arguments[@"desc"];
181 | //构造一条消息
182 | TIMMessage *msg = [TIMMessage new];
183 |
184 | //添加图片
185 | TIMLocationElem *elem = [TIMLocationElem new];
186 | elem.latitude = lat;
187 | elem.longitude = lng;
188 | elem.desc = desc;
189 | if([msg addElem:elem] != 0){
190 | NSLog(@"addElement failed");
191 | }
192 |
193 | TIMConversation *conversation = [[TIMManager sharedInstance] getConversation:TIM_C2C receiver:identifier];
194 | [conversation sendMessage:msg succ:^{
195 | result(@"SendMsg ok");
196 | } fail:^(int code, NSString *msg) {
197 | result([NSString stringWithFormat:@"send message failed. code: %d desc:%@", code, msg]);
198 | }];
199 |
200 | }
201 | else if([@"post_data_test" isEqualToString:call.method]){
202 |
203 | NSLog(@"post_data_test invoke");
204 | self.eventSink(@"hahahahha I am from listener");
205 |
206 | }else if([@"addFriend" isEqualToString:call.method]){
207 |
208 | TIMFriendRequest *req = [[TIMFriendRequest alloc] init];
209 | req.identifier = (NSString *)call.arguments[@"identifier"];
210 | req.addWording =@"请添加我";
211 | req.addSource = @"AddSource_Type_iOS";
212 | [[TIMFriendshipManager sharedInstance] addFriend:req succ:^(TIMFriendResult *addResult) {
213 | if (addResult.result_code == 0)
214 | result(@"添加成功");
215 | else
216 | result([NSString stringWithFormat:@"异常:%ld, %@", (long)addResult.result_code, addResult.result_info]);
217 | } fail:^(int code, NSString *msg) {
218 | result([NSString stringWithFormat:@"失败:%d, %@", code, msg]);
219 | }];
220 |
221 | }else if([@"delFriend" isEqualToString:call.method]){
222 |
223 |
224 | NSMutableArray * del_users = [[NSMutableArray alloc] init];
225 | // 删除好友 iOS_002
226 | [del_users addObject:@"iOS_002"];
227 | // TIM_FRIEND_DEL_BOTH 指定删除双向好友
228 | [[TIMFriendshipManager sharedInstance] deleteFriends:del_users delType:TIM_FRIEND_DEL_BOTH succ:^(NSArray *results) {
229 | for (TIMFriendResult * res in results) {
230 | if (res.result_code != TIM_FRIEND_STATUS_SUCC) {
231 | result([NSString stringWithFormat:@"deleteFriends failed: user=%@ status=%ld", res.identifier, (long)res.result_code]);
232 | }
233 | else {
234 | result([NSString stringWithFormat:@"deleteFriends succ: user=%@ status=%ld", res.identifier, (long)res.result_code]);
235 | }
236 | }
237 | } fail:^(int code, NSString * err) {
238 | result([NSString stringWithFormat:@"deleteFriends failed: code=%d err=%@", code, err]);
239 | }];
240 |
241 | }else if([@"listFriends" isEqualToString:call.method]){
242 |
243 | [[TIMFriendshipManager sharedInstance] getFriendList:^(NSArray * arr) {
244 | NSString *jsonString = [arr yy_modelToJSONString];
245 | result(jsonString);
246 | }fail:^(int code, NSString * err) {
247 | result([NSString stringWithFormat:@"GetFriendList fail: code=%d err=%@", code, err]);
248 | }];
249 |
250 | }else if([@"opFriend" isEqualToString:call.method]){
251 |
252 | NSString *identifier = call.arguments[@"identifier"];
253 | NSString *opTypeStr = call.arguments[@"opTypeStr"];
254 | TIMFriendResponse *response = [[TIMFriendResponse alloc] init];
255 | response.identifier = identifier;
256 | if([opTypeStr isEqualToString:@"Y"]){
257 | response.responseType = TIM_FRIEND_RESPONSE_AGREE_AND_ADD;
258 | }else{
259 | response.responseType = TIM_FRIEND_RESPONSE_REJECT;
260 | }
261 | [[TIMFriendshipManager sharedInstance] doResponse:response succ:^(TIMFriendResult *res) {
262 | if (res.result_code != TIM_FRIEND_STATUS_SUCC) {
263 | result([NSString stringWithFormat:@"deleteFriends failed: user=%@ status=%ld", res.identifier, (long)res.result_code]);
264 | }
265 | else {
266 | result([NSString stringWithFormat:@"deleteFriends succ: user=%@ status=%ld", res.identifier, (long)res.result_code]);
267 | }
268 | } fail:^(int code, NSString *err) {
269 | result([NSString stringWithFormat:@"opFriend fail: code=%d err=%@", code, err]);
270 | }];
271 |
272 | }
273 | else if([@"getUsersProfile" isEqualToString:call.method]){
274 |
275 | NSArray *arr1 = call.arguments[@"users"];
276 |
277 |
278 | [[TIMFriendshipManager sharedInstance] getUsersProfile:arr1 forceUpdate:YES succ:^(NSArray * arr) {
279 | // for (TIMUserProfile * profile in arr) {
280 | // NSLog(@"user=%@", profile);
281 | // }
282 | if (arr !=NULL && arr.count >0) {
283 | NSString *jsonString = [arr yy_modelToJSONString];
284 | result(jsonString);
285 | }else{
286 | result(@"[]");
287 | }
288 | }fail:^(int code, NSString * err) {
289 |
290 | result([NSString stringWithFormat:@"getUsersProfile fail: code=%d err=%@", code, err]);
291 | }];
292 | }
293 | else if([@"setUsersProfile" isEqualToString:call.method]){
294 | NSString *nick = call.arguments[@"nick"];
295 | NSInteger gender = (NSInteger)call.arguments[@"gender"];
296 | NSString *faceUrl = call.arguments[@"faceUrl"];
297 | [[TIMFriendshipManager sharedInstance]modifySelfProfile:@{TIMProfileTypeKey_Nick:nick,TIMProfileTypeKey_FaceUrl:faceUrl,TIMProfileTypeKey_Gender:[NSNumber numberWithInt:gender==1?TIM_GENDER_MALE:TIM_GENDER_FEMALE]} succ:^{
298 | result(@"setUsersProfile succ");
299 | } fail:^(int code, NSString *err) {
300 | result([NSString stringWithFormat:@"GetFriendList fail: code=%d err=%@", code, err]);
301 | }];
302 | }
303 | else {
304 | result(FlutterMethodNotImplemented);
305 | }
306 | }
307 |
308 |
309 | #pragma mark - FlutterStreamHandler
310 | - (FlutterError*)onListenWithArguments:(id)arguments
311 | eventSink:(FlutterEventSink)eventSink {
312 | self.eventSink = eventSink;
313 | // [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
314 | // [self sendBatteryStateEvent];
315 | // [[NSNotificationCenter defaultCenter]
316 | // addObserver:self
317 | // selector:@selector(onBatteryStateDidChange:)
318 | // name:UIDeviceBatteryStateDidChangeNotification
319 | // object:nil];
320 | return nil;
321 | }
322 |
323 | - (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments{
324 | return nil;
325 | }
326 |
327 | #pragma mark - TIMMessageListener
328 | /**
329 | * 新消息回调通知
330 | *
331 | * @param msgs 新消息列表,TIMMessage 类型数组
332 | */
333 | - (void)onNewMessage:(NSArray*)msgs{
334 | if(msgs != nil && msgs.count > 0){
335 | NSMutableArray *dictArray = [[NSMutableArray alloc]init];
336 | for (TIMMessage *message in msgs) {
337 | DimMessage *dimMessage = [DimMessage initWithTIMMessage:message];
338 | [dictArray addObject:dimMessage];
339 | }
340 | NSString *jsonString = [dictArray yy_modelToJSONString];
341 | self.eventSink(jsonString);
342 | }
343 | }
344 |
345 | #pragma mark - TIMRefreshListener
346 | /**
347 | * 会话列表变动
348 | */
349 | - (void)onRefresh{
350 | self.eventSink(@"[]");
351 | }
352 | @end
353 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/MJExtension.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJExtension.h
3 | // MJExtension
4 | //
5 | // Created by mj on 14-1-15.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | // 代码地址:https://github.com/CoderMJLee/MJExtension
8 | // 代码地址:http://code4app.com/ios/%E5%AD%97%E5%85%B8-JSON-%E4%B8%8E%E6%A8%A1%E5%9E%8B%E7%9A%84%E8%BD%AC%E6%8D%A2/5339992a933bf062608b4c57
9 |
10 | #import "NSObject+MJCoding.h"
11 | #import "NSObject+MJProperty.h"
12 | #import "NSObject+MJClass.h"
13 | #import "NSObject+MJKeyValue.h"
14 | #import "NSString+MJExtension.h"
15 | #import "MJExtensionConst.h"
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/MJExtensionConst.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef __MJExtensionConst__H__
3 | #define __MJExtensionConst__H__
4 |
5 | #import
6 |
7 | // 信号量
8 | #define MJExtensionSemaphoreCreate \
9 | static dispatch_semaphore_t signalSemaphore; \
10 | static dispatch_once_t onceTokenSemaphore; \
11 | dispatch_once(&onceTokenSemaphore, ^{ \
12 | signalSemaphore = dispatch_semaphore_create(1); \
13 | });
14 |
15 | #define MJExtensionSemaphoreWait \
16 | dispatch_semaphore_wait(signalSemaphore, DISPATCH_TIME_FOREVER);
17 |
18 | #define MJExtensionSemaphoreSignal \
19 | dispatch_semaphore_signal(signalSemaphore);
20 |
21 | // 过期
22 | #define MJExtensionDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
23 |
24 | // 构建错误
25 | #define MJExtensionBuildError(clazz, msg) \
26 | NSError *error = [NSError errorWithDomain:msg code:250 userInfo:nil]; \
27 | [clazz setMj_error:error];
28 |
29 | // 日志输出
30 | #ifdef DEBUG
31 | #define MJExtensionLog(...) NSLog(__VA_ARGS__)
32 | #else
33 | #define MJExtensionLog(...)
34 | #endif
35 |
36 | /**
37 | * 断言
38 | * @param condition 条件
39 | * @param returnValue 返回值
40 | */
41 | #define MJExtensionAssertError(condition, returnValue, clazz, msg) \
42 | [clazz setMj_error:nil]; \
43 | if ((condition) == NO) { \
44 | MJExtensionBuildError(clazz, msg); \
45 | return returnValue;\
46 | }
47 |
48 | #define MJExtensionAssert2(condition, returnValue) \
49 | if ((condition) == NO) return returnValue;
50 |
51 | /**
52 | * 断言
53 | * @param condition 条件
54 | */
55 | #define MJExtensionAssert(condition) MJExtensionAssert2(condition, )
56 |
57 | /**
58 | * 断言
59 | * @param param 参数
60 | * @param returnValue 返回值
61 | */
62 | #define MJExtensionAssertParamNotNil2(param, returnValue) \
63 | MJExtensionAssert2((param) != nil, returnValue)
64 |
65 | /**
66 | * 断言
67 | * @param param 参数
68 | */
69 | #define MJExtensionAssertParamNotNil(param) MJExtensionAssertParamNotNil2(param, )
70 |
71 | /**
72 | * 打印所有的属性
73 | */
74 | #define MJLogAllIvars \
75 | -(NSString *)description \
76 | { \
77 | return [self mj_keyValues].description; \
78 | }
79 | #define MJExtensionLogAllProperties MJLogAllIvars
80 |
81 | /**
82 | * 类型(属性类型)
83 | */
84 | extern NSString *const MJPropertyTypeInt;
85 | extern NSString *const MJPropertyTypeShort;
86 | extern NSString *const MJPropertyTypeFloat;
87 | extern NSString *const MJPropertyTypeDouble;
88 | extern NSString *const MJPropertyTypeLong;
89 | extern NSString *const MJPropertyTypeLongLong;
90 | extern NSString *const MJPropertyTypeChar;
91 | extern NSString *const MJPropertyTypeBOOL1;
92 | extern NSString *const MJPropertyTypeBOOL2;
93 | extern NSString *const MJPropertyTypePointer;
94 |
95 | extern NSString *const MJPropertyTypeIvar;
96 | extern NSString *const MJPropertyTypeMethod;
97 | extern NSString *const MJPropertyTypeBlock;
98 | extern NSString *const MJPropertyTypeClass;
99 | extern NSString *const MJPropertyTypeSEL;
100 | extern NSString *const MJPropertyTypeId;
101 |
102 | #endif
103 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/MJExtensionConst.m:
--------------------------------------------------------------------------------
1 | #ifndef __MJExtensionConst__M__
2 | #define __MJExtensionConst__M__
3 |
4 | #import
5 |
6 | /**
7 | * 成员变量类型(属性类型)
8 | */
9 | NSString *const MJPropertyTypeInt = @"i";
10 | NSString *const MJPropertyTypeShort = @"s";
11 | NSString *const MJPropertyTypeFloat = @"f";
12 | NSString *const MJPropertyTypeDouble = @"d";
13 | NSString *const MJPropertyTypeLong = @"l";
14 | NSString *const MJPropertyTypeLongLong = @"q";
15 | NSString *const MJPropertyTypeChar = @"c";
16 | NSString *const MJPropertyTypeBOOL1 = @"c";
17 | NSString *const MJPropertyTypeBOOL2 = @"b";
18 | NSString *const MJPropertyTypePointer = @"*";
19 |
20 | NSString *const MJPropertyTypeIvar = @"^{objc_ivar=}";
21 | NSString *const MJPropertyTypeMethod = @"^{objc_method=}";
22 | NSString *const MJPropertyTypeBlock = @"@?";
23 | NSString *const MJPropertyTypeClass = @"#";
24 | NSString *const MJPropertyTypeSEL = @":";
25 | NSString *const MJPropertyTypeId = @"@";
26 |
27 | #endif
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/MJFoundation.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJFoundation.h
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 14/7/16.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface MJFoundation : NSObject
12 | + (BOOL)isClassFromFoundation:(Class)c;
13 | @end
14 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/MJFoundation.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJFoundation.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 14/7/16.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJFoundation.h"
10 | #import "MJExtensionConst.h"
11 | #import
12 |
13 | @implementation MJFoundation
14 |
15 | + (BOOL)isClassFromFoundation:(Class)c
16 | {
17 | if (c == [NSObject class] || c == [NSManagedObject class]) return YES;
18 |
19 | static NSSet *foundationClasses;
20 | static dispatch_once_t onceToken;
21 | dispatch_once(&onceToken, ^{
22 | // 集合中没有NSObject,因为几乎所有的类都是继承自NSObject,具体是不是NSObject需要特殊判断
23 | foundationClasses = [NSSet setWithObjects:
24 | [NSURL class],
25 | [NSDate class],
26 | [NSValue class],
27 | [NSData class],
28 | [NSError class],
29 | [NSArray class],
30 | [NSDictionary class],
31 | [NSString class],
32 | [NSAttributedString class], nil];
33 | });
34 |
35 | __block BOOL result = NO;
36 | [foundationClasses enumerateObjectsUsingBlock:^(Class foundationClass, BOOL *stop) {
37 | if ([c isSubclassOfClass:foundationClass]) {
38 | result = YES;
39 | *stop = YES;
40 | }
41 | }];
42 | return result;
43 | }
44 | @end
45 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/MJProperty.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJProperty.h
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/4/17.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | // 包装一个成员属性
8 |
9 | #import
10 | #import
11 | #import "MJPropertyType.h"
12 | #import "MJPropertyKey.h"
13 |
14 | /**
15 | * 包装一个成员
16 | */
17 | @interface MJProperty : NSObject
18 | /** 成员属性 */
19 | @property (nonatomic, assign) objc_property_t property;
20 | /** 成员属性的名字 */
21 | @property (nonatomic, readonly) NSString *name;
22 |
23 | /** 成员属性的类型 */
24 | @property (nonatomic, readonly) MJPropertyType *type;
25 | /** 成员属性来源于哪个类(可能是父类) */
26 | @property (nonatomic, assign) Class srcClass;
27 |
28 | /**** 同一个成员属性 - 父类和子类的行为可能不一致(originKey、propertyKeys、objectClassInArray) ****/
29 | /** 设置最原始的key */
30 | - (void)setOriginKey:(id)originKey forClass:(Class)c;
31 | /** 对应着字典中的多级key(里面存放的数组,数组里面都是MJPropertyKey对象) */
32 | - (NSArray *)propertyKeysForClass:(Class)c;
33 |
34 | /** 模型数组中的模型类型 */
35 | - (void)setObjectClassInArray:(Class)objectClass forClass:(Class)c;
36 | - (Class)objectClassInArrayForClass:(Class)c;
37 | /**** 同一个成员变量 - 父类和子类的行为可能不一致(key、keys、objectClassInArray) ****/
38 |
39 | /**
40 | * 设置object的成员变量值
41 | */
42 | - (void)setValue:(id)value forObject:(id)object;
43 | /**
44 | * 得到object的成员属性值
45 | */
46 | - (id)valueForObject:(id)object;
47 |
48 | /**
49 | * 初始化
50 | */
51 | + (instancetype)cachedPropertyWithProperty:(objc_property_t)property;
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/MJProperty.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJProperty.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/4/17.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJProperty.h"
10 | #import "MJFoundation.h"
11 | #import "MJExtensionConst.h"
12 | #import
13 |
14 | @interface MJProperty()
15 | @property (strong, nonatomic) NSMutableDictionary *propertyKeysDict;
16 | @property (strong, nonatomic) NSMutableDictionary *objectClassInArrayDict;
17 | @end
18 |
19 | @implementation MJProperty
20 |
21 | #pragma mark - 初始化
22 | - (instancetype)init
23 | {
24 | if (self = [super init]) {
25 | _propertyKeysDict = [NSMutableDictionary dictionary];
26 | _objectClassInArrayDict = [NSMutableDictionary dictionary];
27 | }
28 | return self;
29 | }
30 |
31 | #pragma mark - 缓存
32 | + (instancetype)cachedPropertyWithProperty:(objc_property_t)property
33 | {
34 | MJExtensionSemaphoreCreate
35 | MJExtensionSemaphoreWait
36 | MJProperty *propertyObj = objc_getAssociatedObject(self, property);
37 | if (propertyObj == nil) {
38 | propertyObj = [[self alloc] init];
39 | propertyObj.property = property;
40 | objc_setAssociatedObject(self, property, propertyObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
41 | }
42 | MJExtensionSemaphoreSignal
43 | return propertyObj;
44 | }
45 |
46 | #pragma mark - 公共方法
47 | - (void)setProperty:(objc_property_t)property
48 | {
49 | _property = property;
50 |
51 | MJExtensionAssertParamNotNil(property);
52 |
53 | // 1.属性名
54 | _name = @(property_getName(property));
55 |
56 | // 2.成员类型
57 | NSString *attrs = @(property_getAttributes(property));
58 | NSUInteger dotLoc = [attrs rangeOfString:@","].location;
59 | NSString *code = nil;
60 | NSUInteger loc = 1;
61 | if (dotLoc == NSNotFound) { // 没有,
62 | code = [attrs substringFromIndex:loc];
63 | } else {
64 | code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc)];
65 | }
66 | _type = [MJPropertyType cachedTypeWithCode:code];
67 | }
68 |
69 | /**
70 | * 获得成员变量的值
71 | */
72 | - (id)valueForObject:(id)object
73 | {
74 | if (self.type.KVCDisabled) return [NSNull null];
75 | return [object valueForKey:self.name];
76 | }
77 |
78 | /**
79 | * 设置成员变量的值
80 | */
81 | - (void)setValue:(id)value forObject:(id)object
82 | {
83 | if (self.type.KVCDisabled || value == nil) return;
84 | [object setValue:value forKey:self.name];
85 | }
86 |
87 | /**
88 | * 通过字符串key创建对应的keys
89 | */
90 | - (NSArray *)propertyKeysWithStringKey:(NSString *)stringKey
91 | {
92 | if (stringKey.length == 0) return nil;
93 |
94 | NSMutableArray *propertyKeys = [NSMutableArray array];
95 | // 如果有多级映射
96 | NSArray *oldKeys = [stringKey componentsSeparatedByString:@"."];
97 |
98 | for (NSString *oldKey in oldKeys) {
99 | NSUInteger start = [oldKey rangeOfString:@"["].location;
100 | if (start != NSNotFound) { // 有索引的key
101 | NSString *prefixKey = [oldKey substringToIndex:start];
102 | NSString *indexKey = prefixKey;
103 | if (prefixKey.length) {
104 | MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init];
105 | propertyKey.name = prefixKey;
106 | [propertyKeys addObject:propertyKey];
107 |
108 | indexKey = [oldKey stringByReplacingOccurrencesOfString:prefixKey withString:@""];
109 | }
110 |
111 | /** 解析索引 **/
112 | // 元素
113 | NSArray *cmps = [[indexKey stringByReplacingOccurrencesOfString:@"[" withString:@""] componentsSeparatedByString:@"]"];
114 | for (NSInteger i = 0; i
10 |
11 | typedef enum {
12 | MJPropertyKeyTypeDictionary = 0, // 字典的key
13 | MJPropertyKeyTypeArray // 数组的key
14 | } MJPropertyKeyType;
15 |
16 | /**
17 | * 属性的key
18 | */
19 | @interface MJPropertyKey : NSObject
20 | /** key的名字 */
21 | @property (copy, nonatomic) NSString *name;
22 | /** key的种类,可能是@"10",可能是@"age" */
23 | @property (assign, nonatomic) MJPropertyKeyType type;
24 |
25 | /**
26 | * 根据当前的key,也就是name,从object(字典或者数组)中取值
27 | */
28 | - (id)valueInObject:(id)object;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/MJPropertyKey.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJPropertyKey.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/8/11.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJPropertyKey.h"
10 |
11 | @implementation MJPropertyKey
12 |
13 | - (id)valueInObject:(id)object
14 | {
15 | if ([object isKindOfClass:[NSDictionary class]] && self.type == MJPropertyKeyTypeDictionary) {
16 | return object[self.name];
17 | } else if ([object isKindOfClass:[NSArray class]] && self.type == MJPropertyKeyTypeArray) {
18 | NSArray *array = object;
19 | NSUInteger index = self.name.intValue;
20 | if (index < array.count) return array[index];
21 | return nil;
22 | }
23 | return nil;
24 | }
25 | @end
26 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/MJPropertyType.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJPropertyType.h
3 | // MJExtension
4 | //
5 | // Created by mj on 14-1-15.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | // 包装一种类型
8 |
9 | #import
10 |
11 | /**
12 | * 包装一种类型
13 | */
14 | @interface MJPropertyType : NSObject
15 | /** 类型标识符 */
16 | @property (nonatomic, copy) NSString *code;
17 |
18 | /** 是否为id类型 */
19 | @property (nonatomic, readonly, getter=isIdType) BOOL idType;
20 |
21 | /** 是否为基本数字类型:int、float等 */
22 | @property (nonatomic, readonly, getter=isNumberType) BOOL numberType;
23 |
24 | /** 是否为BOOL类型 */
25 | @property (nonatomic, readonly, getter=isBoolType) BOOL boolType;
26 |
27 | /** 对象类型(如果是基本数据类型,此值为nil) */
28 | @property (nonatomic, readonly) Class typeClass;
29 |
30 | /** 类型是否来自于Foundation框架,比如NSString、NSArray */
31 | @property (nonatomic, readonly, getter = isFromFoundation) BOOL fromFoundation;
32 | /** 类型是否不支持KVC */
33 | @property (nonatomic, readonly, getter = isKVCDisabled) BOOL KVCDisabled;
34 |
35 | /**
36 | * 获得缓存的类型对象
37 | */
38 | + (instancetype)cachedTypeWithCode:(NSString *)code;
39 | @end
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/MJPropertyType.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJPropertyType.m
3 | // MJExtension
4 | //
5 | // Created by mj on 14-1-15.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJPropertyType.h"
10 | #import "MJExtension.h"
11 | #import "MJFoundation.h"
12 | #import "MJExtensionConst.h"
13 |
14 | @implementation MJPropertyType
15 |
16 | + (instancetype)cachedTypeWithCode:(NSString *)code
17 | {
18 | MJExtensionAssertParamNotNil2(code, nil);
19 |
20 | static NSMutableDictionary *types;
21 | static dispatch_once_t onceToken;
22 | dispatch_once(&onceToken, ^{
23 | types = [NSMutableDictionary dictionary];
24 | });
25 |
26 | MJExtensionSemaphoreCreate
27 | MJExtensionSemaphoreWait
28 | MJPropertyType *type = types[code];
29 | if (type == nil) {
30 | type = [[self alloc] init];
31 | type.code = code;
32 | types[code] = type;
33 | }
34 | MJExtensionSemaphoreSignal
35 | return type;
36 | }
37 |
38 | #pragma mark - 公共方法
39 | - (void)setCode:(NSString *)code
40 | {
41 | _code = code;
42 |
43 | MJExtensionAssertParamNotNil(code);
44 |
45 | if ([code isEqualToString:MJPropertyTypeId]) {
46 | _idType = YES;
47 | } else if (code.length == 0) {
48 | _KVCDisabled = YES;
49 | } else if (code.length > 3 && [code hasPrefix:@"@\""]) {
50 | // 去掉@"和",截取中间的类型名称
51 | _code = [code substringWithRange:NSMakeRange(2, code.length - 3)];
52 | _typeClass = NSClassFromString(_code);
53 | _fromFoundation = [MJFoundation isClassFromFoundation:_typeClass];
54 | _numberType = [_typeClass isSubclassOfClass:[NSNumber class]];
55 |
56 | } else if ([code isEqualToString:MJPropertyTypeSEL] ||
57 | [code isEqualToString:MJPropertyTypeIvar] ||
58 | [code isEqualToString:MJPropertyTypeMethod]) {
59 | _KVCDisabled = YES;
60 | }
61 |
62 | // 是否为数字类型
63 | NSString *lowerCode = _code.lowercaseString;
64 | NSArray *numberTypes = @[MJPropertyTypeInt, MJPropertyTypeShort, MJPropertyTypeBOOL1, MJPropertyTypeBOOL2, MJPropertyTypeFloat, MJPropertyTypeDouble, MJPropertyTypeLong, MJPropertyTypeLongLong, MJPropertyTypeChar];
65 | if ([numberTypes containsObject:lowerCode]) {
66 | _numberType = YES;
67 |
68 | if ([lowerCode isEqualToString:MJPropertyTypeBOOL1]
69 | || [lowerCode isEqualToString:MJPropertyTypeBOOL2]) {
70 | _boolType = YES;
71 | }
72 | }
73 | }
74 | @end
75 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/NSObject+MJClass.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJClass.h
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/8/11.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | * 遍历所有类的block(父类)
13 | */
14 | typedef void (^MJClassesEnumeration)(Class c, BOOL *stop);
15 |
16 | /** 这个数组中的属性名才会进行字典和模型的转换 */
17 | typedef NSArray * (^MJAllowedPropertyNames)(void);
18 | /** 这个数组中的属性名才会进行归档 */
19 | typedef NSArray * (^MJAllowedCodingPropertyNames)(void);
20 |
21 | /** 这个数组中的属性名将会被忽略:不进行字典和模型的转换 */
22 | typedef NSArray * (^MJIgnoredPropertyNames)(void);
23 | /** 这个数组中的属性名将会被忽略:不进行归档 */
24 | typedef NSArray * (^MJIgnoredCodingPropertyNames)(void);
25 |
26 | /**
27 | * 类相关的扩展
28 | */
29 | @interface NSObject (MJClass)
30 | /**
31 | * 遍历所有的类
32 | */
33 | + (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration;
34 | + (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration;
35 |
36 | #pragma mark - 属性白名单配置
37 | /**
38 | * 这个数组中的属性名才会进行字典和模型的转换
39 | *
40 | * @param allowedPropertyNames 这个数组中的属性名才会进行字典和模型的转换
41 | */
42 | + (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
43 |
44 | /**
45 | * 这个数组中的属性名才会进行字典和模型的转换
46 | */
47 | + (NSMutableArray *)mj_totalAllowedPropertyNames;
48 |
49 | #pragma mark - 属性黑名单配置
50 | /**
51 | * 这个数组中的属性名将会被忽略:不进行字典和模型的转换
52 | *
53 | * @param ignoredPropertyNames 这个数组中的属性名将会被忽略:不进行字典和模型的转换
54 | */
55 | + (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames;
56 |
57 | /**
58 | * 这个数组中的属性名将会被忽略:不进行字典和模型的转换
59 | */
60 | + (NSMutableArray *)mj_totalIgnoredPropertyNames;
61 |
62 | #pragma mark - 归档属性白名单配置
63 | /**
64 | * 这个数组中的属性名才会进行归档
65 | *
66 | * @param allowedCodingPropertyNames 这个数组中的属性名才会进行归档
67 | */
68 | + (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames;
69 |
70 | /**
71 | * 这个数组中的属性名才会进行字典和模型的转换
72 | */
73 | + (NSMutableArray *)mj_totalAllowedCodingPropertyNames;
74 |
75 | #pragma mark - 归档属性黑名单配置
76 | /**
77 | * 这个数组中的属性名将会被忽略:不进行归档
78 | *
79 | * @param ignoredCodingPropertyNames 这个数组中的属性名将会被忽略:不进行归档
80 | */
81 | + (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames;
82 |
83 | /**
84 | * 这个数组中的属性名将会被忽略:不进行归档
85 | */
86 | + (NSMutableArray *)mj_totalIgnoredCodingPropertyNames;
87 |
88 | #pragma mark - 内部使用
89 | + (void)mj_setupBlockReturnValue:(id (^)(void))block key:(const char *)key;
90 | @end
91 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/NSObject+MJClass.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJClass.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/8/11.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "NSObject+MJClass.h"
10 | #import "NSObject+MJCoding.h"
11 | #import "NSObject+MJKeyValue.h"
12 | #import "MJFoundation.h"
13 | #import
14 |
15 | static const char MJAllowedPropertyNamesKey = '\0';
16 | static const char MJIgnoredPropertyNamesKey = '\0';
17 | static const char MJAllowedCodingPropertyNamesKey = '\0';
18 | static const char MJIgnoredCodingPropertyNamesKey = '\0';
19 |
20 | @implementation NSObject (MJClass)
21 |
22 | + (NSMutableDictionary *)classDictForKey:(const void *)key
23 | {
24 | static NSMutableDictionary *allowedPropertyNamesDict;
25 | static NSMutableDictionary *ignoredPropertyNamesDict;
26 | static NSMutableDictionary *allowedCodingPropertyNamesDict;
27 | static NSMutableDictionary *ignoredCodingPropertyNamesDict;
28 |
29 | static dispatch_once_t onceToken;
30 | dispatch_once(&onceToken, ^{
31 | allowedPropertyNamesDict = [NSMutableDictionary dictionary];
32 | ignoredPropertyNamesDict = [NSMutableDictionary dictionary];
33 | allowedCodingPropertyNamesDict = [NSMutableDictionary dictionary];
34 | ignoredCodingPropertyNamesDict = [NSMutableDictionary dictionary];
35 | });
36 |
37 | if (key == &MJAllowedPropertyNamesKey) return allowedPropertyNamesDict;
38 | if (key == &MJIgnoredPropertyNamesKey) return ignoredPropertyNamesDict;
39 | if (key == &MJAllowedCodingPropertyNamesKey) return allowedCodingPropertyNamesDict;
40 | if (key == &MJIgnoredCodingPropertyNamesKey) return ignoredCodingPropertyNamesDict;
41 | return nil;
42 | }
43 |
44 | + (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration
45 | {
46 | // 1.没有block就直接返回
47 | if (enumeration == nil) return;
48 |
49 | // 2.停止遍历的标记
50 | BOOL stop = NO;
51 |
52 | // 3.当前正在遍历的类
53 | Class c = self;
54 |
55 | // 4.开始遍历每一个类
56 | while (c && !stop) {
57 | // 4.1.执行操作
58 | enumeration(c, &stop);
59 |
60 | // 4.2.获得父类
61 | c = class_getSuperclass(c);
62 |
63 | if ([MJFoundation isClassFromFoundation:c]) break;
64 | }
65 | }
66 |
67 | + (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration
68 | {
69 | // 1.没有block就直接返回
70 | if (enumeration == nil) return;
71 |
72 | // 2.停止遍历的标记
73 | BOOL stop = NO;
74 |
75 | // 3.当前正在遍历的类
76 | Class c = self;
77 |
78 | // 4.开始遍历每一个类
79 | while (c && !stop) {
80 | // 4.1.执行操作
81 | enumeration(c, &stop);
82 |
83 | // 4.2.获得父类
84 | c = class_getSuperclass(c);
85 | }
86 | }
87 |
88 | #pragma mark - 属性黑名单配置
89 | + (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames
90 | {
91 | [self mj_setupBlockReturnValue:ignoredPropertyNames key:&MJIgnoredPropertyNamesKey];
92 | }
93 |
94 | + (NSMutableArray *)mj_totalIgnoredPropertyNames
95 | {
96 | return [self mj_totalObjectsWithSelector:@selector(mj_ignoredPropertyNames) key:&MJIgnoredPropertyNamesKey];
97 | }
98 |
99 | #pragma mark - 归档属性黑名单配置
100 | + (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames
101 | {
102 | [self mj_setupBlockReturnValue:ignoredCodingPropertyNames key:&MJIgnoredCodingPropertyNamesKey];
103 | }
104 |
105 | + (NSMutableArray *)mj_totalIgnoredCodingPropertyNames
106 | {
107 | return [self mj_totalObjectsWithSelector:@selector(mj_ignoredCodingPropertyNames) key:&MJIgnoredCodingPropertyNamesKey];
108 | }
109 |
110 | #pragma mark - 属性白名单配置
111 | + (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
112 | {
113 | [self mj_setupBlockReturnValue:allowedPropertyNames key:&MJAllowedPropertyNamesKey];
114 | }
115 |
116 | + (NSMutableArray *)mj_totalAllowedPropertyNames
117 | {
118 | return [self mj_totalObjectsWithSelector:@selector(mj_allowedPropertyNames) key:&MJAllowedPropertyNamesKey];
119 | }
120 |
121 | #pragma mark - 归档属性白名单配置
122 | + (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames
123 | {
124 | [self mj_setupBlockReturnValue:allowedCodingPropertyNames key:&MJAllowedCodingPropertyNamesKey];
125 | }
126 |
127 | + (NSMutableArray *)mj_totalAllowedCodingPropertyNames
128 | {
129 | return [self mj_totalObjectsWithSelector:@selector(mj_allowedCodingPropertyNames) key:&MJAllowedCodingPropertyNamesKey];
130 | }
131 |
132 | #pragma mark - block和方法处理:存储block的返回值
133 | + (void)mj_setupBlockReturnValue:(id (^)(void))block key:(const char *)key
134 | {
135 | if (block) {
136 | objc_setAssociatedObject(self, key, block(), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
137 | } else {
138 | objc_setAssociatedObject(self, key, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
139 | }
140 |
141 | // 清空数据
142 | MJExtensionSemaphoreCreate
143 | MJExtensionSemaphoreWait
144 | [[self classDictForKey:key] removeAllObjects];
145 | MJExtensionSemaphoreSignal
146 | }
147 |
148 | + (NSMutableArray *)mj_totalObjectsWithSelector:(SEL)selector key:(const char *)key
149 | {
150 | MJExtensionSemaphoreCreate
151 | MJExtensionSemaphoreWait
152 |
153 | NSMutableArray *array = [self classDictForKey:key][NSStringFromClass(self)];
154 | if (array == nil) {
155 | // 创建、存储
156 | [self classDictForKey:key][NSStringFromClass(self)] = array = [NSMutableArray array];
157 |
158 | if ([self respondsToSelector:selector]) {
159 | #pragma clang diagnostic push
160 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
161 | NSArray *subArray = [self performSelector:selector];
162 | #pragma clang diagnostic pop
163 | if (subArray) {
164 | [array addObjectsFromArray:subArray];
165 | }
166 | }
167 |
168 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
169 | NSArray *subArray = objc_getAssociatedObject(c, key);
170 | [array addObjectsFromArray:subArray];
171 | }];
172 | }
173 |
174 | MJExtensionSemaphoreSignal
175 |
176 | return array;
177 | }
178 | @end
179 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/NSObject+MJCoding.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJCoding.h
3 | // MJExtension
4 | //
5 | // Created by mj on 14-1-15.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "MJExtensionConst.h"
11 |
12 | /**
13 | * Codeing协议
14 | */
15 | @protocol MJCoding
16 | @optional
17 | /**
18 | * 这个数组中的属性名才会进行归档
19 | */
20 | + (NSArray *)mj_allowedCodingPropertyNames;
21 | /**
22 | * 这个数组中的属性名将会被忽略:不进行归档
23 | */
24 | + (NSArray *)mj_ignoredCodingPropertyNames;
25 | @end
26 |
27 | @interface NSObject (MJCoding)
28 | /**
29 | * 解码(从文件中解析对象)
30 | */
31 | - (void)mj_decode:(NSCoder *)decoder;
32 | /**
33 | * 编码(将对象写入文件中)
34 | */
35 | - (void)mj_encode:(NSCoder *)encoder;
36 | @end
37 |
38 | /**
39 | 归档的实现
40 | */
41 | #define MJCodingImplementation \
42 | - (id)initWithCoder:(NSCoder *)decoder \
43 | { \
44 | if (self = [super init]) { \
45 | [self mj_decode:decoder]; \
46 | } \
47 | return self; \
48 | } \
49 | \
50 | - (void)encodeWithCoder:(NSCoder *)encoder \
51 | { \
52 | [self mj_encode:encoder]; \
53 | }
54 |
55 | #define MJExtensionCodingImplementation MJCodingImplementation
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/NSObject+MJCoding.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJCoding.m
3 | // MJExtension
4 | //
5 | // Created by mj on 14-1-15.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "NSObject+MJCoding.h"
10 | #import "NSObject+MJClass.h"
11 | #import "NSObject+MJProperty.h"
12 | #import "MJProperty.h"
13 |
14 | @implementation NSObject (MJCoding)
15 |
16 | - (void)mj_encode:(NSCoder *)encoder
17 | {
18 | Class clazz = [self class];
19 |
20 | NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames];
21 | NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames];
22 |
23 | [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
24 | // 检测是否被忽略
25 | if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
26 | if ([ignoredCodingPropertyNames containsObject:property.name]) return;
27 |
28 | id value = [property valueForObject:self];
29 | if (value == nil) return;
30 | [encoder encodeObject:value forKey:property.name];
31 | }];
32 | }
33 |
34 | - (void)mj_decode:(NSCoder *)decoder
35 | {
36 | Class clazz = [self class];
37 |
38 | NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames];
39 | NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames];
40 |
41 | [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
42 | // 检测是否被忽略
43 | if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
44 | if ([ignoredCodingPropertyNames containsObject:property.name]) return;
45 |
46 | id value = [decoder decodeObjectForKey:property.name];
47 | if (value == nil) { // 兼容以前的MJExtension版本
48 | value = [decoder decodeObjectForKey:[@"_" stringByAppendingString:property.name]];
49 | }
50 | if (value == nil) return;
51 | [property setValue:value forObject:self];
52 | }];
53 | }
54 | @end
55 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/NSObject+MJKeyValue.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJKeyValue.h
3 | // MJExtension
4 | //
5 | // Created by mj on 13-8-24.
6 | // Copyright (c) 2013年 小码哥. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "MJExtensionConst.h"
11 | #import
12 | #import "MJProperty.h"
13 |
14 | /**
15 | * KeyValue协议
16 | */
17 | @protocol MJKeyValue
18 | @optional
19 | /**
20 | * 只有这个数组中的属性名才允许进行字典和模型的转换
21 | */
22 | + (NSArray *)mj_allowedPropertyNames;
23 |
24 | /**
25 | * 这个数组中的属性名将会被忽略:不进行字典和模型的转换
26 | */
27 | + (NSArray *)mj_ignoredPropertyNames;
28 |
29 | /**
30 | * 将属性名换为其他key去字典中取值
31 | *
32 | * @return 字典中的key是属性名,value是从字典中取值用的key
33 | */
34 | + (NSDictionary *)mj_replacedKeyFromPropertyName;
35 |
36 | /**
37 | * 将属性名换为其他key去字典中取值
38 | *
39 | * @return 从字典中取值用的key
40 | */
41 | + (id)mj_replacedKeyFromPropertyName121:(NSString *)propertyName;
42 |
43 | /**
44 | * 数组中需要转换的模型类
45 | *
46 | * @return 字典中的key是数组属性名,value是数组中存放模型的Class(Class类型或者NSString类型)
47 | */
48 | + (NSDictionary *)mj_objectClassInArray;
49 |
50 | /**
51 | * 旧值换新值,用于过滤字典中的值
52 | *
53 | * @param oldValue 旧值
54 | *
55 | * @return 新值
56 | */
57 | - (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property;
58 |
59 | /**
60 | * 当字典转模型完毕时调用
61 | */
62 | - (void)mj_keyValuesDidFinishConvertingToObject;
63 | - (void)mj_keyValuesDidFinishConvertingToObject:(NSDictionary *)keyValues;
64 |
65 | /**
66 | * 当模型转字典完毕时调用
67 | */
68 | - (void)mj_objectDidFinishConvertingToKeyValues;
69 | @end
70 |
71 | @interface NSObject (MJKeyValue)
72 | #pragma mark - 类方法
73 | /**
74 | * 字典转模型过程中遇到的错误
75 | */
76 | + (NSError *)mj_error;
77 |
78 | /**
79 | * 模型转字典时,字典的key是否参考replacedKeyFromPropertyName等方法(父类设置了,子类也会继承下来)
80 | */
81 | + (void)mj_referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference;
82 |
83 | #pragma mark - 对象方法
84 | /**
85 | * 将字典的键值对转成模型属性
86 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString)
87 | */
88 | - (instancetype)mj_setKeyValues:(id)keyValues;
89 |
90 | /**
91 | * 将字典的键值对转成模型属性
92 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString)
93 | * @param context CoreData上下文
94 | */
95 | - (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
96 |
97 | /**
98 | * 将模型转成字典
99 | * @return 字典
100 | */
101 | - (NSMutableDictionary *)mj_keyValues;
102 | - (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys;
103 | - (NSMutableDictionary *)mj_keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys;
104 |
105 | /**
106 | * 通过模型数组来创建一个字典数组
107 | * @param objectArray 模型数组
108 | * @return 字典数组
109 | */
110 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray;
111 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys;
112 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys;
113 |
114 | #pragma mark - 字典转模型
115 | /**
116 | * 通过字典来创建一个模型
117 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString)
118 | * @return 新建的对象
119 | */
120 | + (instancetype)mj_objectWithKeyValues:(id)keyValues;
121 |
122 | /**
123 | * 通过字典来创建一个CoreData模型
124 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString)
125 | * @param context CoreData上下文
126 | * @return 新建的对象
127 | */
128 | + (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
129 |
130 | /**
131 | * 通过plist来创建一个模型
132 | * @param filename 文件名(仅限于mainBundle中的文件)
133 | * @return 新建的对象
134 | */
135 | + (instancetype)mj_objectWithFilename:(NSString *)filename;
136 |
137 | /**
138 | * 通过plist来创建一个模型
139 | * @param file 文件全路径
140 | * @return 新建的对象
141 | */
142 | + (instancetype)mj_objectWithFile:(NSString *)file;
143 |
144 | #pragma mark - 字典数组转模型数组
145 | /**
146 | * 通过字典数组来创建一个模型数组
147 | * @param keyValuesArray 字典数组(可以是NSDictionary、NSData、NSString)
148 | * @return 模型数组
149 | */
150 | + (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray;
151 |
152 | /**
153 | * 通过字典数组来创建一个模型数组
154 | * @param keyValuesArray 字典数组(可以是NSDictionary、NSData、NSString)
155 | * @param context CoreData上下文
156 | * @return 模型数组
157 | */
158 | + (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context;
159 |
160 | /**
161 | * 通过plist来创建一个模型数组
162 | * @param filename 文件名(仅限于mainBundle中的文件)
163 | * @return 模型数组
164 | */
165 | + (NSMutableArray *)mj_objectArrayWithFilename:(NSString *)filename;
166 |
167 | /**
168 | * 通过plist来创建一个模型数组
169 | * @param file 文件全路径
170 | * @return 模型数组
171 | */
172 | + (NSMutableArray *)mj_objectArrayWithFile:(NSString *)file;
173 |
174 | #pragma mark - 转换为JSON
175 | /**
176 | * 转换为JSON Data
177 | */
178 | - (NSData *)mj_JSONData;
179 | /**
180 | * 转换为字典或者数组
181 | */
182 | - (id)mj_JSONObject;
183 | /**
184 | * 转换为JSON 字符串
185 | */
186 | - (NSString *)mj_JSONString;
187 | @end
188 |
189 | @interface NSObject (MJKeyValueDeprecated_v_2_5_16)
190 | - (instancetype)setKeyValues:(id)keyValue MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
191 | - (instancetype)setKeyValues:(id)keyValues error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
192 | - (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
193 | - (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
194 | + (void)referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
195 | - (NSMutableDictionary *)keyValues MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
196 | - (NSMutableDictionary *)keyValuesWithError:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
197 | - (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
198 | - (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
199 | - (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
200 | - (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
201 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
202 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
203 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
204 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
205 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
206 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
207 | + (instancetype)objectWithKeyValues:(id)keyValues MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
208 | + (instancetype)objectWithKeyValues:(id)keyValues error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
209 | + (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
210 | + (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
211 | + (instancetype)objectWithFilename:(NSString *)filename MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
212 | + (instancetype)objectWithFilename:(NSString *)filename error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
213 | + (instancetype)objectWithFile:(NSString *)file MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
214 | + (instancetype)objectWithFile:(NSString *)file error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
215 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
216 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
217 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
218 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
219 | + (NSMutableArray *)objectArrayWithFilename:(NSString *)filename MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
220 | + (NSMutableArray *)objectArrayWithFilename:(NSString *)filename error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
221 | + (NSMutableArray *)objectArrayWithFile:(NSString *)file MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
222 | + (NSMutableArray *)objectArrayWithFile:(NSString *)file error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
223 | - (NSData *)JSONData MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
224 | - (id)JSONObject MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
225 | - (NSString *)JSONString MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
226 | @end
227 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/NSObject+MJProperty.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJProperty.h
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/4/17.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "MJExtensionConst.h"
11 |
12 | @class MJProperty;
13 |
14 | /**
15 | * 遍历成员变量用的block
16 | *
17 | * @param property 成员的包装对象
18 | * @param stop YES代表停止遍历,NO代表继续遍历
19 | */
20 | typedef void (^MJPropertiesEnumeration)(MJProperty *property, BOOL *stop);
21 |
22 | /** 将属性名换为其他key去字典中取值 */
23 | typedef NSDictionary * (^MJReplacedKeyFromPropertyName)(void);
24 | typedef id (^MJReplacedKeyFromPropertyName121)(NSString *propertyName);
25 | /** 数组中需要转换的模型类 */
26 | typedef NSDictionary * (^MJObjectClassInArray)(void);
27 | /** 用于过滤字典中的值 */
28 | typedef id (^MJNewValueFromOldValue)(id object, id oldValue, MJProperty *property);
29 |
30 | /**
31 | * 成员属性相关的扩展
32 | */
33 | @interface NSObject (MJProperty)
34 | #pragma mark - 遍历
35 | /**
36 | * 遍历所有的成员
37 | */
38 | + (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration;
39 |
40 | #pragma mark - 新值配置
41 | /**
42 | * 用于过滤字典中的值
43 | *
44 | * @param newValueFormOldValue 用于过滤字典中的值
45 | */
46 | + (void)mj_setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue;
47 | + (id)mj_getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property;
48 |
49 | #pragma mark - key配置
50 | /**
51 | * 将属性名换为其他key去字典中取值
52 | *
53 | * @param replacedKeyFromPropertyName 将属性名换为其他key去字典中取值
54 | */
55 | + (void)mj_setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName;
56 | /**
57 | * 将属性名换为其他key去字典中取值
58 | *
59 | * @param replacedKeyFromPropertyName121 将属性名换为其他key去字典中取值
60 | */
61 | + (void)mj_setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121;
62 |
63 | #pragma mark - array model class配置
64 | /**
65 | * 数组中需要转换的模型类
66 | *
67 | * @param objectClassInArray 数组中需要转换的模型类
68 | */
69 | + (void)mj_setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray;
70 | @end
71 |
72 | @interface NSObject (MJPropertyDeprecated_v_2_5_16)
73 | + (void)enumerateProperties:(MJPropertiesEnumeration)enumeration MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
74 | + (void)setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
75 | + (id)getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
76 | + (void)setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
77 | + (void)setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121 MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
78 | + (void)setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
79 | @end
80 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/NSObject+MJProperty.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJProperty.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/4/17.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "NSObject+MJProperty.h"
10 | #import "NSObject+MJKeyValue.h"
11 | #import "NSObject+MJCoding.h"
12 | #import "NSObject+MJClass.h"
13 | #import "MJProperty.h"
14 | #import "MJFoundation.h"
15 | #import
16 |
17 | #pragma clang diagnostic push
18 | #pragma clang diagnostic ignored "-Wundeclared-selector"
19 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
20 |
21 | static const char MJReplacedKeyFromPropertyNameKey = '\0';
22 | static const char MJReplacedKeyFromPropertyName121Key = '\0';
23 | static const char MJNewValueFromOldValueKey = '\0';
24 | static const char MJObjectClassInArrayKey = '\0';
25 |
26 | static const char MJCachedPropertiesKey = '\0';
27 |
28 | @implementation NSObject (Property)
29 |
30 | + (NSMutableDictionary *)propertyDictForKey:(const void *)key
31 | {
32 | static NSMutableDictionary *replacedKeyFromPropertyNameDict;
33 | static NSMutableDictionary *replacedKeyFromPropertyName121Dict;
34 | static NSMutableDictionary *newValueFromOldValueDict;
35 | static NSMutableDictionary *objectClassInArrayDict;
36 | static NSMutableDictionary *cachedPropertiesDict;
37 |
38 | static dispatch_once_t onceToken;
39 | dispatch_once(&onceToken, ^{
40 | replacedKeyFromPropertyNameDict = [NSMutableDictionary dictionary];
41 | replacedKeyFromPropertyName121Dict = [NSMutableDictionary dictionary];
42 | newValueFromOldValueDict = [NSMutableDictionary dictionary];
43 | objectClassInArrayDict = [NSMutableDictionary dictionary];
44 | cachedPropertiesDict = [NSMutableDictionary dictionary];
45 | });
46 |
47 | if (key == &MJReplacedKeyFromPropertyNameKey) return replacedKeyFromPropertyNameDict;
48 | if (key == &MJReplacedKeyFromPropertyName121Key) return replacedKeyFromPropertyName121Dict;
49 | if (key == &MJNewValueFromOldValueKey) return newValueFromOldValueDict;
50 | if (key == &MJObjectClassInArrayKey) return objectClassInArrayDict;
51 | if (key == &MJCachedPropertiesKey) return cachedPropertiesDict;
52 | return nil;
53 | }
54 |
55 | #pragma mark - --私有方法--
56 | + (id)propertyKey:(NSString *)propertyName
57 | {
58 | MJExtensionAssertParamNotNil2(propertyName, nil);
59 |
60 | __block id key = nil;
61 | // 查看有没有需要替换的key
62 | if ([self respondsToSelector:@selector(mj_replacedKeyFromPropertyName121:)]) {
63 | key = [self mj_replacedKeyFromPropertyName121:propertyName];
64 | }
65 | // 兼容旧版本
66 | if ([self respondsToSelector:@selector(replacedKeyFromPropertyName121:)]) {
67 | key = [self performSelector:@selector(replacedKeyFromPropertyName121) withObject:propertyName];
68 | }
69 |
70 | // 调用block
71 | if (!key) {
72 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
73 | MJReplacedKeyFromPropertyName121 block = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyName121Key);
74 | if (block) {
75 | key = block(propertyName);
76 | }
77 | if (key) *stop = YES;
78 | }];
79 | }
80 |
81 | // 查看有没有需要替换的key
82 | if ((!key || [key isEqual:propertyName]) && [self respondsToSelector:@selector(mj_replacedKeyFromPropertyName)]) {
83 | key = [self mj_replacedKeyFromPropertyName][propertyName];
84 | }
85 | // 兼容旧版本
86 | if ((!key || [key isEqual:propertyName]) && [self respondsToSelector:@selector(replacedKeyFromPropertyName)]) {
87 | key = [self performSelector:@selector(replacedKeyFromPropertyName)][propertyName];
88 | }
89 |
90 | if (!key || [key isEqual:propertyName]) {
91 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
92 | NSDictionary *dict = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyNameKey);
93 | if (dict) {
94 | key = dict[propertyName];
95 | }
96 | if (key && ![key isEqual:propertyName]) *stop = YES;
97 | }];
98 | }
99 |
100 | // 2.用属性名作为key
101 | if (!key) key = propertyName;
102 |
103 | return key;
104 | }
105 |
106 | + (Class)propertyObjectClassInArray:(NSString *)propertyName
107 | {
108 | __block id clazz = nil;
109 | if ([self respondsToSelector:@selector(mj_objectClassInArray)]) {
110 | clazz = [self mj_objectClassInArray][propertyName];
111 | }
112 | // 兼容旧版本
113 | if ([self respondsToSelector:@selector(objectClassInArray)]) {
114 | clazz = [self performSelector:@selector(objectClassInArray)][propertyName];
115 | }
116 |
117 | if (!clazz) {
118 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
119 | NSDictionary *dict = objc_getAssociatedObject(c, &MJObjectClassInArrayKey);
120 | if (dict) {
121 | clazz = dict[propertyName];
122 | }
123 | if (clazz) *stop = YES;
124 | }];
125 | }
126 |
127 | // 如果是NSString类型
128 | if ([clazz isKindOfClass:[NSString class]]) {
129 | clazz = NSClassFromString(clazz);
130 | }
131 | return clazz;
132 | }
133 |
134 | #pragma mark - --公共方法--
135 | + (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration
136 | {
137 | // 获得成员变量
138 | NSArray *cachedProperties = [self properties];
139 |
140 | // 遍历成员变量
141 | BOOL stop = NO;
142 | for (MJProperty *property in cachedProperties) {
143 | enumeration(property, &stop);
144 | if (stop) break;
145 | }
146 | }
147 |
148 | #pragma mark - 公共方法
149 | + (NSMutableArray *)properties
150 | {
151 | NSMutableArray *cachedProperties = [self propertyDictForKey:&MJCachedPropertiesKey][NSStringFromClass(self)];
152 |
153 | if (cachedProperties == nil) {
154 | MJExtensionSemaphoreCreate
155 | MJExtensionSemaphoreWait
156 |
157 | if (cachedProperties == nil) {
158 | cachedProperties = [NSMutableArray array];
159 |
160 | [self mj_enumerateClasses:^(__unsafe_unretained Class c, BOOL *stop) {
161 | // 1.获得所有的成员变量
162 | unsigned int outCount = 0;
163 | objc_property_t *properties = class_copyPropertyList(c, &outCount);
164 |
165 | // 2.遍历每一个成员变量
166 | for (unsigned int i = 0; i
10 | #import "MJExtensionConst.h"
11 |
12 | @interface NSString (MJExtension)
13 | /**
14 | * 驼峰转下划线(loveYou -> love_you)
15 | */
16 | - (NSString *)mj_underlineFromCamel;
17 | /**
18 | * 下划线转驼峰(love_you -> loveYou)
19 | */
20 | - (NSString *)mj_camelFromUnderline;
21 | /**
22 | * 首字母变大写
23 | */
24 | - (NSString *)mj_firstCharUpper;
25 | /**
26 | * 首字母变小写
27 | */
28 | - (NSString *)mj_firstCharLower;
29 |
30 | - (BOOL)mj_isPureInt;
31 |
32 | - (NSURL *)mj_url;
33 | @end
34 |
35 | @interface NSString (MJExtensionDeprecated_v_2_5_16)
36 | - (NSString *)underlineFromCamel MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
37 | - (NSString *)camelFromUnderline MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
38 | - (NSString *)firstCharUpper MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
39 | - (NSString *)firstCharLower MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
40 | - (BOOL)isPureInt MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
41 | - (NSURL *)url MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
42 | @end
43 |
--------------------------------------------------------------------------------
/ios/Classes/MJExtension/NSString+MJExtension.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+MJExtension.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/6/7.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "NSString+MJExtension.h"
10 |
11 | @implementation NSString (MJExtension)
12 | - (NSString *)mj_underlineFromCamel
13 | {
14 | if (self.length == 0) return self;
15 | NSMutableString *string = [NSMutableString string];
16 | for (NSUInteger i = 0; i= 2) [string appendString:[cmp substringFromIndex:1]];
40 | } else {
41 | [string appendString:cmp];
42 | }
43 | }
44 | return string;
45 | }
46 |
47 | - (NSString *)mj_firstCharLower
48 | {
49 | if (self.length == 0) return self;
50 | NSMutableString *string = [NSMutableString string];
51 | [string appendString:[NSString stringWithFormat:@"%c", [self characterAtIndex:0]].lowercaseString];
52 | if (self.length >= 2) [string appendString:[self substringFromIndex:1]];
53 | return string;
54 | }
55 |
56 | - (NSString *)mj_firstCharUpper
57 | {
58 | if (self.length == 0) return self;
59 | NSMutableString *string = [NSMutableString string];
60 | [string appendString:[NSString stringWithFormat:@"%c", [self characterAtIndex:0]].uppercaseString];
61 | if (self.length >= 2) [string appendString:[self substringFromIndex:1]];
62 | return string;
63 | }
64 |
65 | - (BOOL)mj_isPureInt
66 | {
67 | NSScanner *scan = [NSScanner scannerWithString:self];
68 | int val;
69 | return [scan scanInt:&val] && [scan isAtEnd];
70 | }
71 |
72 | - (NSURL *)mj_url
73 | {
74 | // [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"!$&'()*+,-./:;=?@_~%#[]"]];
75 | #pragma clang diagnostic push
76 | #pragma clang diagnostic ignored"-Wdeprecated-declarations"
77 | return [NSURL URLWithString:(NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL,kCFStringEncodingUTF8))];
78 | #pragma clang diagnostic pop
79 | }
80 | @end
81 |
82 | @implementation NSString (MJExtensionDeprecated_v_2_5_16)
83 | - (NSString *)underlineFromCamel
84 | {
85 | return self.mj_underlineFromCamel;
86 | }
87 |
88 | - (NSString *)camelFromUnderline
89 | {
90 | return self.mj_camelFromUnderline;
91 | }
92 |
93 | - (NSString *)firstCharLower
94 | {
95 | return self.mj_firstCharLower;
96 | }
97 |
98 | - (NSString *)firstCharUpper
99 | {
100 | return self.mj_firstCharUpper;
101 | }
102 |
103 | - (BOOL)isPureInt
104 | {
105 | return self.mj_isPureInt;
106 | }
107 |
108 | - (NSURL *)url
109 | {
110 | return self.mj_url;
111 | }
112 | @end
113 |
--------------------------------------------------------------------------------
/ios/dim.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
3 | #
4 | Pod::Spec.new do |s|
5 | s.name = 'dim'
6 | s.version = '0.2.7'
7 | s.summary = 'TIMSDK for flutter'
8 | s.description = <<-DESC
9 | A new flutter plugin project.
10 | DESC
11 | s.homepage = 'https://gitee.com/gameOverFlow/dim'
12 | s.license = { :file => '../LICENSE' }
13 | s.author = { 'brzhang' => '1595819400@qq.com' }
14 | s.source = { :path => '.' }
15 | s.source_files = 'Classes/**/*'
16 | s.public_header_files = 'Classes/**/*.h'
17 | s.dependency 'Flutter'
18 | s.dependency 'YYModel'
19 | s.dependency 'TXIMSDK_iOS'
20 | s.ios.deployment_target = '8.0'
21 | end
22 |
23 |
--------------------------------------------------------------------------------
/lib/dim.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'package:flutter/services.dart';
3 |
4 | class Dim {
5 | factory Dim() {
6 | if (_instance == null) {
7 | final MethodChannel methodChannel = const MethodChannel('dim_method');
8 | final EventChannel eventChannel = const EventChannel('dim_event');
9 | _instance = new Dim.private(methodChannel, eventChannel);
10 | }
11 | return _instance;
12 | }
13 |
14 | Dim.private(this._methodChannel, this._eventChannel);
15 |
16 | final MethodChannel _methodChannel;
17 |
18 | final EventChannel _eventChannel;
19 |
20 | Future get platformVersion async {
21 | final String version =
22 | await _methodChannel.invokeMethod('getPlatformVersion');
23 | return version;
24 | }
25 |
26 | static Dim _instance;
27 |
28 | Stream _listener;
29 |
30 | Stream get onMessage {
31 | if (_listener == null) {
32 | _listener = _eventChannel
33 | .receiveBroadcastStream()
34 | .map((dynamic event) => _parseBatteryState(event));
35 | }
36 | return _listener;
37 | }
38 |
39 | ///im初始化
40 | Future init(int appid) async {
41 | return await _methodChannel.invokeMethod("init", {
42 | 'appid': appid,
43 | });
44 | }
45 |
46 | ///im登录
47 | Future imLogin(String identifier, String sig) async {
48 | return await _methodChannel.invokeMethod("im_login", {
49 | 'identifier': identifier,
50 | 'userSig': sig,
51 | });
52 | }
53 |
54 | ///im登出
55 | Future imLogout() async {
56 | return await _methodChannel.invokeMethod("im_logout");
57 | }
58 |
59 | ///获取会话列表
60 | Future getConversations() async {
61 | return await _methodChannel.invokeMethod('getConversations');
62 | }
63 |
64 | ///删除会话
65 | Future delConversation(String identifier) async {
66 | return await _methodChannel.invokeMethod(
67 | 'delConversation', {'identifier': identifier});
68 | }
69 |
70 | ///获取一个会话的消息,暂不支持流式查询
71 | ///identifier 会话id
72 | ///count 获取消息数量 ,默认50条
73 | ///ctype 1 私信,2群聊 ,默认是私信
74 | Future getMessages(String identifier,
75 | [int count = 50, int ctype = 1]) async {
76 | return await _methodChannel.invokeMethod('getMessages', {
77 | 'identifier': identifier,
78 | 'count': count,
79 | 'ctype': ctype
80 | });
81 | }
82 |
83 | ///发送文本消息
84 | Future sendTextMessages(String identifier, String content) async {
85 | return await _methodChannel.invokeMethod('sendTextMessages',
86 | {'identifier': identifier, 'content': content});
87 | }
88 |
89 | ///发送图片消息
90 | ///imagePath eg for android : Environment.getExternalStorageDirectory() + "/DCIM/Camera/1.jpg"
91 | Future sendImageMessages(String identifier, String imagePath) async {
92 | return await _methodChannel.invokeMethod('sendImageMessages',
93 | {'identifier': identifier, 'image_path': imagePath});
94 | }
95 |
96 | ///发送语音消息
97 | ///soundPath eg for android : Environment.getExternalStorageDirectory() + "/sound.mp3"
98 | Future sendSoundMessages(String identifier, String soundPath,
99 | [int duration = 10]) async {
100 | return await _methodChannel.invokeMethod(
101 | 'sendSoundMessages', {
102 | 'identifier': identifier,
103 | 'sound_path': soundPath,
104 | 'duration': duration
105 | });
106 | }
107 |
108 | ///发送位置消息
109 | ///eg:
110 | ///lat 113.93
111 | ///lng 22.54
112 | ///desc 腾讯大厦
113 | Future sendLocationMessages(
114 | String identifier, double lat, double lng, String desc) async {
115 | return await _methodChannel.invokeMethod('sendLocation', {
116 | 'identifier': identifier,
117 | 'lat': lat,
118 | 'lng': lng,
119 | 'desc': desc,
120 | });
121 | }
122 |
123 | ///添加好友
124 | ///
125 | Future addFriend(String identifier) async {
126 | return await _methodChannel
127 | .invokeMethod("addFriend", {'identifier': identifier});
128 | }
129 |
130 | ///删除好友
131 | ///
132 | Future delFriend(String identifier) async {
133 | return await _methodChannel
134 | .invokeMethod("delFriend", {'identifier': identifier});
135 | }
136 |
137 | ///获取好友列表
138 | ///
139 | Future listFriends(String identifier) async {
140 | return await _methodChannel.invokeMethod(
141 | "listFriends", {'identifier': identifier});
142 | }
143 |
144 | ///处理好友的请求,接受/拒绝
145 | ///opTypeStr 接受传 Y
146 | ///opTypeStr 拒绝传 N
147 | Future opFriend(String identifier, String opTypeStr) async {
148 | return await _methodChannel.invokeMethod("opFriend",
149 | {'identifier': identifier, 'opTypeStr': opTypeStr});
150 | }
151 |
152 | ///获取用户资料
153 | ///param user is a list ["usersf1","jiofoea2"]
154 | Future getUsersProfile(List users) async {
155 | return await _methodChannel
156 | .invokeMethod("getUsersProfile", {'users': users});
157 | }
158 |
159 | ///设置个人资料
160 | Future setUsersProfile(
161 | int gender, String nick, String faceUrl) async {
162 | return await _methodChannel.invokeMethod("setUsersProfile",
163 | {'gender': gender, 'nick': nick, 'faceUrl': faceUrl});
164 | }
165 |
166 | ///测试使用eventChannel推送数据过来
167 | Future postDataTest() async {
168 | return await _methodChannel.invokeMethod("post_data_test");
169 | }
170 |
171 | dynamic _parseBatteryState(event) {
172 | return event;
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/lib/manger.dart:
--------------------------------------------------------------------------------
1 | class Manger {
2 | static final Manger _singleton = new Manger._internal();
3 |
4 | factory Manger() {
5 | return _singleton;
6 | }
7 |
8 | Manger._internal() {
9 | // initialization logic here
10 | }
11 | // rest of the class
12 | }
13 |
14 | abstract class MessageListener {
15 | void makePeopleLaugh();
16 | }
17 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: dim
2 | description: Convenient integration tencent imsdk, developers can easily use imsdk on flutter.reading READEME, then you can enjoy imsdk on flutter。
3 | version: 0.2.7
4 | author: brzhang <1595819400@qq.com>
5 | homepage: https://github.com/bravekingzhang/dim
6 |
7 | dependencies:
8 | flutter:
9 | sdk: flutter
10 |
11 | # For information on the generic Dart part of this file, see the
12 | # following page: https://www.dartlang.org/tools/pub/pubspec
13 |
14 | # The following section is specific to Flutter.
15 | flutter:
16 | plugin:
17 | androidPackage: com.brzhang.flutter.dim
18 | pluginClass: DimPlugin
19 |
20 | # To add assets to your plugin package, add an assets section, like this:
21 | # assets:
22 | # - images/a_dot_burr.jpeg
23 | # - images/a_dot_ham.jpeg
24 | #
25 | # For details regarding assets in packages, see
26 | # https://flutter.io/assets-and-images/#from-packages
27 | #
28 | # An image asset can refer to one or more resolution-specific "variants", see
29 | # https://flutter.io/assets-and-images/#resolution-aware.
30 |
31 | # To add custom fonts to your plugin package, add a fonts section here,
32 | # in this "flutter" section. Each entry in this list should have a
33 | # "family" key with the font family name, and a "fonts" key with a
34 | # list giving the asset and other descriptors for the font. For
35 | # example:
36 | # fonts:
37 | # - family: Schyler
38 | # fonts:
39 | # - asset: fonts/Schyler-Regular.ttf
40 | # - asset: fonts/Schyler-Italic.ttf
41 | # style: italic
42 | # - family: Trajan Pro
43 | # fonts:
44 | # - asset: fonts/TrajanPro.ttf
45 | # - asset: fonts/TrajanPro_Bold.ttf
46 | # weight: 700
47 | #
48 | # For details regarding fonts in packages, see
49 | # https://flutter.io/custom-fonts/#from-packages
50 | environment:
51 | sdk: ">=2.1.0 <3.0.0"
52 |
--------------------------------------------------------------------------------