├── .gitattributes ├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README_CN.md ├── android ├── .gitignore ├── build.gradle ├── gradle.properties ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── me │ └── ele │ └── dna │ ├── DLog.java │ ├── DnaClient.java │ ├── DnaPlugin.java │ ├── IResultCallBack.java │ ├── exception │ ├── AbnormalConstructorException.java │ ├── AbnormalMethodException.java │ └── ArgsException.java │ ├── finder │ ├── BaseDnaFinder.java │ ├── ConstructorFinder.java │ ├── MethodFinder.java │ └── ProxyFinder.java │ ├── model │ ├── DnaClassInfo.java │ ├── DnaResult.java │ ├── MethodInfo.java │ ├── MethodTacker.java │ ├── ParameterInfo.java │ └── ResultInfo.java │ └── util │ ├── DnaUtils.java │ └── GsonUtils.java ├── dna.iml ├── example ├── .gitignore ├── .metadata ├── android │ ├── app │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── me │ │ │ │ │ └── ele │ │ │ │ │ └── dna_example │ │ │ │ │ ├── DnaTest.java │ │ │ │ │ ├── DnaVersion.java │ │ │ │ │ └── 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 │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── dna-annotations │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── me │ │ │ └── ele │ │ │ └── dna_annotations │ │ │ ├── DnaConstants.java │ │ │ ├── DnaMethod.java │ │ │ └── DnaParamFieldList.java │ ├── dna-compiler │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── me │ │ │ │ └── ele │ │ │ │ └── dna_compiler │ │ │ │ ├── BaseDnaElement.java │ │ │ │ ├── DnaClassFinder.java │ │ │ │ ├── DnaConstructorInfo.java │ │ │ │ ├── DnaMethodInfo.java │ │ │ │ ├── DnaPackageFinder.java │ │ │ │ ├── DnaProcessor.java │ │ │ │ └── ParamInfo.java │ │ │ └── resources │ │ │ └── META-INF │ │ │ └── services │ │ │ └── javax.annotation.processing.Processor │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── ios │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ └── contents.xcworkspacedata │ └── 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.lock ├── pubspec.yaml └── test │ └── widget_test.dart ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── DnaPlugin.h │ ├── DnaPlugin.m │ ├── NSObject+DnaRuntime.h │ └── NSObject+DnaRuntime.m └── dna.podspec ├── lib ├── dna.dart ├── native_context.dart └── native_object.dart ├── pubspec.lock ├── pubspec.yaml └── test └── dna_test.dart /.gitattributes: -------------------------------------------------------------------------------- 1 | *.* linguist-language=Dart 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | /.idea 4 | .packages 5 | .pub/ 6 | build/ 7 | /.idea/workspace.xml -------------------------------------------------------------------------------- /.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: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * TODO: Describe initial release. 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | TODO: Add your license here. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dna 2 | ### [中文文档👉](./README_CN.md) 3 | ### [相关文章](https://juejin.im/post/5e5f1d41518825495b29a05b) 4 | dart native access. A lightweight dart to native super channel plugin, You can use it to invoke any native code directly in dart code. 5 | 6 | Supported Platform(Language): 7 | 8 | - iOS(Objective-C) 9 | - Android(Java) 10 | 11 | The primary scenario: 12 | 13 | - Implement some simple channels directly in dart code; 14 | - Native code that are calling using dna can also be hot-reloaded. 15 | 16 | 17 | ## Add dependency 18 | 1. Add folllowing code to the *pubspec.yaml* file in your flutter project: 19 | 20 | ``` 21 | dependencies: 22 | dna: 23 | git:git@github.com:Assuner-Lee/dna.git 24 | ``` 25 | 26 | > Reference: [https://flutter.dev/docs/development/packages-and-plugins/using-packages](https://flutter.dev/docs/development/packages-and-plugins/using-packages) 27 | 28 | 2. import header file in dart code: 29 | 30 | ``` 31 | import 'package:dna/dna.dart'; 32 | ``` 33 | 3. add gradle dependency in Android project: 34 | 35 | ``` 36 | implementation 'me.ele:dna-annotations:1.2.0' 37 | annotationProcessor 'me.ele:dna-compiler:1.2.0' 38 | ``` 39 | 4. add following conconfiguration in Android project's proguard-rules 40 | 41 | ``` 42 | -keep class **.Dna_Class_Proxy { *; } 43 | -keep class me.ele.dna_compiler.** { *; } 44 | -keep class me.ele.dna.** { *; } 45 | ``` 46 | 47 | ## Usage 48 | 49 | ### Main class 50 | 51 | - `NativeContext`: You can use it to describe *Native code* by *Dart code*, then call `context.execute()` to execute the final *Native code* on associated platform and get the returned value. 52 | 53 | - `NativeObject`: Used to identify the *native variable*. The caller `NativeObject ` can call the `invoke` method to pass in the *method name* and the *parameter array args list* in the context of the `NativeContext` to get the return value `NativeObject` object. 54 | 55 | 56 | The API of `NativeContext` is consistent. Now we will make a detailed introduction for call *ObjC* using `ObjCContext`, Then call *Java* using `JAVAContext`. 57 | 58 | ### Call ObjC using Dart 59 | 60 | `ObjCContext` is the final executor on iOS platform. 61 | 62 | #### Context call supported 63 | ##### Returned value as caller 64 | 65 | ObjC code 66 | 67 | ``` 68 | NSString *versionString = [[UIDevice currentDevice] systemVersion]; 69 | // Return versionString using fluter channel 70 | ``` 71 | Dart code 72 | 73 | ``` 74 | ObjCContext context = ObjCContext(); 75 | NativeObject UIDevice = context.classFromString('UIDevice'); 76 | NativeObject device = UIDevice.invoke(method: 'currentDevice'); 77 | NativeObject version = device.invoke(method: 'systemVersion'); 78 | 79 | context.returnVar = version; // Can be omitted, See:Quick use of instantiated objects in JSON supported 80 | 81 | // Get native execution results directly 82 | var versionString = await context.execute(); 83 | ``` 84 | 85 | ##### Returned value as parameters 86 | 87 | ObjC code 88 | 89 | ``` 90 | NSString *versionString = [[UIDevice currentDevice] systemVersion]; 91 | NSString *platform = @"iOS-"; 92 | versionString = [platform stringByAppendingString: versionString]; 93 | 94 | // Return versionString using fluter channel 95 | ``` 96 | Dart code 97 | 98 | ``` 99 | ObjCContext context = ObjCContext(); 100 | NativeClass UIDevice = context.classFromString('UIDevice'); 101 | NativeObject device = UIDevice.invoke(method: 'currentDevice'); 102 | NativeObject version = device.invoke(method: 'systemVersion'); 103 | NativeObject platform = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']); 104 | version = platform.invoke(method: 'stringByAppendingString:', args: [version]); 105 | 106 | context.returnVar = version; // Can be omitted, See:Quick use of instantiated objects in JSON supported 107 | 108 | // Get native execution results directly 109 | var versionString = await context.execute(); 110 | ``` 111 | 112 | #### Chaining calls supported 113 | 114 | ObjC code 115 | 116 | ``` 117 | NSString *versionString = [[UIDevice currentDevice] systemVersion]; 118 | versionString = [@"iOS-" stringByAppendingString: versionString]; 119 | 120 | // Return versionString using fluter channel 121 | ``` 122 | 123 | Dart code 124 | 125 | ``` 126 | ObjCContext context = ObjCContext(); 127 | NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion'); 128 | version = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']).invoke(method: 'stringByAppendingString:', args: [version]); 129 | 130 | context.returnVar = version; // Can be omitted, See:Quick use of instantiated objects in JSON supported 131 | 132 | 133 | // Get native execution results directly 134 | var versionString = await context.execute(); 135 | ``` 136 | 137 | 138 | > **Something about the final returned value of the `context`** 139 | 140 | > `context.returnVar` is the marker of the final returned value of `context`. 141 | 142 | > 1. When setting `context.returnVar`, you can get the *Native* variable corresponding to the `NativeObject`; 143 | > 2. Without setting `context.returnVar`, execute to the last `invoke`, if there is a return value, it will be the final returned value of `context`; if not, it will return a `null` value. 144 | 145 | > ``` 146 | > ObjCContext context = ObjCContext(); 147 | > context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion'); 148 | > 149 | > // Get native execution results directly 150 | > var versionString = await context.execute(); 151 | > ``` 152 | 153 | #### Quick use of instantiated objects in JSON supported 154 | 155 | Sometimes, we need to directly instantiate an object with `JSON`. 156 | 157 | ObjC code 158 | 159 | ``` 160 | ClassA *objectA = [ClassA new]; 161 | objectA.a = 1; 162 | objectA.b = @"sss"; 163 | ``` 164 | 165 | Dart code 166 | 167 | One way 168 | 169 | ``` 170 | ObjCContext context = ObjCContext(); 171 | NativeObject objectA = context.classFromString('ClassA').invoke(method: 'new'); 172 | objectA.invoke(method: 'setA:', args: [1]); 173 | objectA.invoke(method: 'setB:', args: ['sss']); 174 | ``` 175 | 176 | The other way 177 | 178 | ``` 179 | ObjCContext context = ObjCContext(); 180 | NativeObject objectA = context.newNativeObjectFromJSON({'a':1,'b':'sss'}, 'ClassA'); 181 | ``` 182 | 183 | ### Call Java using Dart 184 | 185 | `JAVAContext` is the final executor on Android 186 | platform, it has all the fetures that `ObjCContext` have. 187 | 188 | - Context call supported; 189 | - Chaining calls supported; 190 | - Quick use of instantiated objects in JSON supported. 191 | 192 | In addition, it additionally supports the instantiation of an object from the constructor. 193 | 194 | #### The instantiation of an object from the constructor supported 195 | 196 | Java code 197 | 198 | ``` 199 | String platform = new String("android"); 200 | ``` 201 | 202 | Dart code 203 | 204 | ``` 205 | NativeObject version = context 206 | .newJavaObjectFromConstructor('java.lang.String', ["android "]) 207 | 208 | ``` 209 | 210 | ### Fast organization of dual platform code 211 | 212 | We provide you with a quick way to initialize and execute context: 213 | 214 | ``` 215 | static Future traversingNative(ObjCContextBuilder(ObjCContext objcContext), JAVAContextBuilder(JAVAContext javaContext)) async { 216 | NativeContext nativeContext; 217 | if (Platform.isIOS) { 218 | nativeContext = ObjCContext(); 219 | ObjCContextBuilder(nativeContext); 220 | } else if (Platform.isAndroid) { 221 | nativeContext = JAVAContext(); 222 | JAVAContextBuilder(nativeContext); 223 | } 224 | return executeNativeContext(nativeContext); 225 | } 226 | ``` 227 | 228 | So you can write the native call of two platforms quickly: 229 | 230 | ``` 231 | platformVersion = await Dna.traversingNative((ObjCContext context) { 232 | NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion'); 233 | version = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']).invoke(method: 'stringByAppendingString:', args: [version]); 234 | 235 | context.returnVar = version; // Can be omitted 236 | }, (JAVAContext context) { 237 | NativeObject versionId = context.newJavaObjectFromConstructor('com.example.dna_example.DnaTest', null).invoke(method: 'getDnaVersion').invoke(method: 'getVersion'); 238 | NativeObject version = context.newJavaObjectFromConstructor('java.lang.String', ["android "]).invoke(method: "concat", args: [versionId]); 239 | 240 | context.returnVar = version; // Can be omitted 241 | }); 242 | ``` 243 | 244 | ## Principle introduction 245 | 246 | dna **does not involve the transformation from a dart object to a native object**, it also **does not care about the life cycle of the native object**, but **focuses on describing the `context` of native method calls**, When `context.execute()` called, a native method is called through `channel`, and the call stack is passed in the form of `JSON` for native dynamic parsing and calling. 247 | 248 | for example, Let's take a look at the previous Dart code: 249 | 250 | ``` 251 | ObjCContext context = ObjCContext(); 252 | NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion'); 253 | version = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']).invoke(method: 'stringByAppendingString:', args: [version]); 254 | 255 | context.returnVar = version; // Can be omitted, See: Quick use of instantiated objects in JSON supported 256 | 257 | // Get native execution results directly 258 | var versionString = await context.execute(); 259 | ``` 260 | 261 | What the `execute()` method of `NativeContext` actually called is the following method: 262 | 263 | ``` 264 | static Future executeNativeContext(NativeContext context) async { 265 | return await _channel.invokeMethod('executeNativeContext', context.toJSON()); 266 | } 267 | ``` 268 | 269 | In the native executed method corresponding to the `executeNativeContext` method, the received 'JSON' is as follows: 270 | 271 | ``` 272 | { 273 | "_objectJSONWrappers": [], 274 | "returnVar": { 275 | "_objectId": "_objectId_WyWRIsLl" 276 | }, 277 | "_invocationNodes": [{ 278 | "returnVar": { 279 | "_objectId": "_objectId_KNWtiPuM" 280 | }, 281 | "object": { 282 | "_objectId": "_objectId_qyfACNGb", 283 | "clsName": "UIDevice" 284 | }, 285 | "method": "currentDevice" 286 | }, { 287 | "returnVar": { 288 | "_objectId": "_objectId_haPktBlL" 289 | }, 290 | "object": { 291 | "_objectId": "_objectId_KNWtiPuM" 292 | }, 293 | "method": "systemVersion" 294 | }, { 295 | "object": { 296 | "_objectId": "_objectId_UAUcgnOD", 297 | "clsName": "NSString" 298 | }, 299 | "method": "stringWithString:", 300 | "args": ["iOS-"], 301 | "returnVar": { 302 | "_objectId": "_objectId_UiCMaHAN" 303 | } 304 | }, { 305 | "object": { 306 | "_objectId": "_objectId_UiCMaHAN" 307 | }, 308 | "method": "stringByAppendingString:", 309 | "args": [{ 310 | "_objectId": "_objectId_haPktBlL" 311 | }], 312 | "returnVar": { 313 | "_objectId": "_objectId_WyWRIsLl" 314 | } 315 | }] 316 | } 317 | ``` 318 | 319 | Then we maintain an `objectsInContextMap` on the native side, its key is `objectId`, and the value is native object. 320 | 321 | `_invocationNodes` is the call context of the method, let's take a look at one of them. 322 | 323 | Here we will dynamically call `[UIDevice currentDevice]`, and return the object to `objectsInContextMap` with `_objectId_KNWtiPuM` stored in `returnVar` as the key. 324 | 325 | ``` 326 | { 327 | "returnVar": { 328 | "_objectId": "_objectId_KNWtiPuM" 329 | }, 330 | "object": { 331 | "_objectId": "_objectId_qyfACNGb", 332 | "clsName": "UIDevice" 333 | }, 334 | "method": "currentDevice" 335 | }, 336 | ``` 337 | 338 | Here, the object `_objectId_KNWtiPuM` is the returned value of the previous method. Take it out from the `objectsInContextMap`, continue the dynamic call, and store the new returned value with the `_objectId` of the `returnVar` as the key. 339 | 340 | ``` 341 | { 342 | "returnVar": { 343 | "_objectId": "_objectId_haPktBlL" 344 | }, 345 | "object": { 346 | "_objectId": "_objectId_KNWtiPuM" // Will find the real object in objectsInContextMap 347 | }, 348 | "method": "systemVersion" 349 | } 350 | ``` 351 | 352 | dna supports automatic package loading and unpacking when the method has parameters, such as `int<->NSNumber`, If the parameter is not one of the 15 basic types specified by `channel` but `NativeObject`, we will find the object from `objectsInContextMap` and put it into the actual parameter list. 353 | 354 | ``` 355 | { 356 | "object": { 357 | "_objectId": "_objectId_UiCMaHAN" 358 | }, 359 | "method": "stringByAppendingString:", 360 | "args": [{ 361 | "_objectId": "_objectId_haPktBlL" // Will find the real object in objectsInContextMap 362 | }], 363 | "returnVar": { 364 | "_objectId": "_objectId_WyWRIsLl" 365 | } 366 | ``` 367 | 368 | If final `returnVar` is set, The object corresponding to the `returnVar objectId` will be found from the `objectsInContextMap` and called back as the return value of the `channel `, if not, take the return value of the last `invocation`(if any). 369 | 370 | ## Author 371 | 372 | - yongguang.lyg@alibaba-inc.com 373 | - zhengguang.zzg@alibaba-inc.com 374 | - zyd178591@alibaba-inc.com 375 | 376 | ## Change log 377 | | version | note | 378 | | ------ | ------ | 379 | | 0.1.0 | alpha version | 380 | 381 | ## License 382 | 383 | dna is available under the MIT license. See the LICENSE file for more info. 384 | 385 | ## Other Tips 386 | 387 | - Code warehouse will be migrated to **eleme** in the near future; 388 | - You are welcome to star, issue and PR. 389 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # dna 2 | ### [README👉](./README.md) 3 | 一个flutter plugin. 轻量级的Dart到Native的超级通道, 可直接在dart代码中调用原生代码,目前支持安卓 JAVA 和 iOS ObjC. 主要用途: 4 | 5 | * 可以把channel中的原生代码写在dart代码中, 6 | * 让原生代码也支持热加载. 7 | 8 | # 开始 9 | 1.这里建议使用 `git` 依赖, 在flutter工程 pubspec.yaml 添加如下: 10 | 11 | ``` 12 | dependencies: 13 | dna: 14 | git:git@github.com:Assuner-Lee/dna.git 15 | ``` 16 | 17 | > [参考文档: https://flutter.dev/docs/development/packages-and-plugins/using-packages](https://flutter.dev/docs/development/packages-and-plugins/using-packages) 18 | 19 | 2.在dart代码中引入头文件 20 | 21 | ``` 22 | import 'package:dna/dna.dart'; 23 | 24 | ``` 25 | 26 | 3.在android项目中引入依赖 27 | 28 | ``` 29 | implementation 'me.ele:dna-annotations:1.2.0' 30 | annotationProcessor 'me.ele:dna-compiler:1.2.0' 31 | 32 | ``` 33 | 使用模块化开发时,可以在子模块中单独引入dna-annotations包,从而获得注解方法的能力 34 | 35 | 4.在android项目中加入反混淆配置 36 | 37 | ``` 38 | -keep class **.Dna_Class_Proxy { *; } 39 | -keep class me.ele.dna_compiler.** { *; } 40 | -keep class me.ele.dna.** { *; } 41 | 42 | ``` 43 | 44 | # 使用介绍 45 | `dna` 在`Dart代码`中: 46 | 47 | * 定义了 `NativeContext 类` ,以执行 `Dart 代码` 的方式,描述 `Native 代码` 调用上下文(调用栈);最后调用 `context.execute()` 执行对应平台的 `Native 代码` 并返回结果。 48 | 49 | * 定义了 `NativeObject 类` ,用于标识 `Native 变量`. `调用者 NativeObject 对象` 可借助 `所在NativeContext上下文` 调用 `invoke方法` 传入 `方法名 method` 和 `参数数组 args list` ,得到 `返回值NativeObject对象` 。 50 | 51 | `NativeContext 子类` 的API是一致的. 下面先详细介绍通过 `ObjCContext` 调用 `ObjC` ,再区别介绍 `JAVAContext` 调用 `JAVA`. 52 | 53 | ## Dart 调用 ObjC 54 | `ObjCContext` 仅在iOS平台会实际执行. 55 | 56 | ### 1. 支持上下文调用 57 | ##### (1) 返回值作为调用者 58 | ObjC代码 59 | 60 | ``` 61 | NSString *versionString = [[UIDevice currentDevice] systemVersion]; 62 | // 通过channel返回versionString 63 | ``` 64 | Dart 代码 65 | 66 | ``` 67 | ObjCContext context = ObjCContext(); 68 | NativeObject UIDevice = context.classFromString('UIDevice'); 69 | NativeObject device = UIDevice.invoke(method: 'currentDevice'); 70 | NativeObject version = device.invoke(method: 'systemVersion'); 71 | 72 | context.returnVar = version; // 可省略设定最终返回值, 参考3 73 | 74 | // 直接获得原生执行结果 75 | var versionString = await context.execute(); 76 | ``` 77 | 78 | ##### (2) 返回值作为参数 79 | ObjC代码 80 | 81 | ``` 82 | NSString *versionString = [[UIDevice currentDevice] systemVersion]; 83 | NSString *platform = @"iOS-"; 84 | versionString = [platform stringByAppendingString: versionString]; 85 | 86 | // 通过channel返回versionString 87 | ``` 88 | Dart 代码 89 | 90 | ``` 91 | ObjCContext context = ObjCContext(); 92 | NativeClass UIDevice = context.classFromString('UIDevice'); 93 | NativeObject device = UIDevice.invoke(method: 'currentDevice'); 94 | NativeObject version = device.invoke(method: 'systemVersion'); 95 | NativeObject platform = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']); 96 | version = platform.invoke(method: 'stringByAppendingString:', args: [version]); 97 | 98 | context.returnVar = version; // 可省略设定最终返回值, 参考3 99 | 100 | // 直接获得原生执行结果 101 | var versionString = await context.execute(); 102 | ``` 103 | 104 | 105 | ### 2. 支持链式调用 106 | ObjC代码 107 | 108 | ``` 109 | NSString *versionString = [[UIDevice currentDevice] systemVersion]; 110 | versionString = [@"iOS-" stringByAppendingString: versionString]; 111 | 112 | // 通过channel返回versionString 113 | ``` 114 | 115 | Dart 代码 116 | 117 | ``` 118 | ObjCContext context = ObjCContext(); 119 | NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion'); 120 | version = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']).invoke(method: 'stringByAppendingString:', args: [version]); 121 | 122 | context.returnVar = version; // 可省略设定最终返回值, 参考3 123 | 124 | // 直接获得原生执行结果 125 | var versionString = await context.execute(); 126 | ``` 127 | 128 | ### *关于Context的最终返回值 129 | 130 | `context.returnVar` 是 `context` 最终执行完毕返回值的标记 131 | 132 | 1. 设定context.returnVar: 返回该NativeObject对应的Native变量 133 | 2. 不设定context.returnVar: 执行到最后一个invoke,如果有返回值,作为context的最终返回值; 无返回值则返回空值; 134 | 135 | ``` 136 | ObjCContext context = ObjCContext(); 137 | context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion'); 138 | 139 | // 直接获得原生执行结果 140 | var versionString = await context.execute(); 141 | ``` 142 | 143 | ### 3.支持快捷使用JSON中实例化对象 144 | 或许有些时候,我们需要用 `JSON` 直接实例化一个对象. 145 | 146 | ObjC代码 147 | 148 | ``` 149 | ClassA *objectA = [ClassA new]; 150 | objectA.a = 1; 151 | objectA.b = @"sss"; 152 | ``` 153 | 154 | 一般时候,这样写 155 | Dart 代码 156 | 157 | ``` 158 | ObjCContext context = ObjCContext(); 159 | NativeObject objectA = context.classFromString('ClassA').invoke(method: 'new'); 160 | objectA.invoke(method: 'setA:', args: [1]); 161 | objectA.invoke(method: 'setB:', args: ['sss']); 162 | ``` 163 | 也可以从JSON中生成 164 | 165 | ``` 166 | ObjCContext context = ObjCContext(); 167 | NativeObject objectA = context.newNativeObjectFromJSON({'a':1,'b':'sss'}, 'ClassA'); 168 | ``` 169 | 170 | ## Dart 调用 JAVA 171 | `JAVAContext` 仅在安卓系统中会被实际执行. `JAVAContext` 拥有上述 `ObjCContext` `Dart调ObjC` 的全部特性. 172 | 173 | * 支持上下文调用 174 | * 支持链式调用 175 | * 支持用JSON中实例化对象 176 | 177 | 另外,额外支持了从构造器中实例化一个对象 178 | 179 | ### 4. 支持快捷使用构造器实例化对象 180 | JAVA代码 181 | 182 | ``` 183 | String platform = new String("android"); 184 | ``` 185 | 186 | Dart 代码 187 | 188 | ``` 189 | NativeObject version = context 190 | .newJavaObjectFromConstructor('java.lang.String', ["android "]) 191 | 192 | ``` 193 | 194 | 195 | ## 快捷组织双端代码 196 | 提供了一个快捷的方法来 初始化和执行 context. 197 | 198 | ``` 199 | static Future traversingNative(ObjCContextBuilder(ObjCContext objcContext), JAVAContextBuilder(JAVAContext javaContext)) async { 200 | NativeContext nativeContext; 201 | if (Platform.isIOS) { 202 | nativeContext = ObjCContext(); 203 | ObjCContextBuilder(nativeContext); 204 | } else if (Platform.isAndroid) { 205 | nativeContext = JAVAContext(); 206 | JAVAContextBuilder(nativeContext); 207 | } 208 | return executeNativeContext(nativeContext); 209 | } 210 | 211 | ``` 212 | 可以快速书写两端的原生调用 213 | 214 | ``` 215 | platformVersion = await Dna.traversingNative((ObjCContext context) { 216 | NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion'); 217 | version = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']).invoke(method: 'stringByAppendingString:', args: [version]); 218 | 219 | context.returnVar = version; // 该句可省略 220 | }, (JAVAContext context) { 221 | NativeObject versionId = context.newJavaObjectFromConstructor('com.example.dna_example.DnaTest', null).invoke(method: 'getDnaVersion').invoke(method: 'getVersion'); 222 | NativeObject version = context.newJavaObjectFromConstructor('java.lang.String', ["android "]).invoke(method: "concat", args: [versionId]); 223 | 224 | context.returnVar = version; // 该句可省略 225 | }); 226 | ``` 227 | 228 | # 原理简介 229 | `dna` 并不涉及` dart对象到Native对象的转换` ,也不关心 `Native对象的生命周期`,而是着重与描述原生方法调用的上下文,在 `context execute` 时通过 `channel` 调用一次原生方法,把调用栈以 `JSON` 的形式传过去供原生动态解析调用。 230 | 231 | 如前文的中 dart 代码 232 | 233 | ``` 234 | ObjCContext context = ObjCContext(); 235 | NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion'); 236 | version = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']).invoke(method: 'stringByAppendingString:', args: [version]); 237 | 238 | context.returnVar = version; // 可省略设定最终返回值, 参考3 239 | 240 | // 直接获得原生执行结果 241 | var versionString = await context.execute(); 242 | ``` 243 | `NativeContext的execute()` 方法,实际调用了 244 | 245 | ``` 246 | static Future executeNativeContext(NativeContext context) async { 247 | return await _channel.invokeMethod('executeNativeContext', context.toJSON()); 248 | } 249 | ``` 250 | 251 | 在 `原生的 executeNativeContext` 对应执行的方法中,接收到的 `JSON` 是这样的 252 | 253 | ``` 254 | { 255 | "_objectJSONWrappers": [], 256 | "returnVar": { 257 | "_objectId": "_objectId_WyWRIsLl" 258 | }, 259 | "_invocationNodes": [{ 260 | "returnVar": { 261 | "_objectId": "_objectId_KNWtiPuM" 262 | }, 263 | "object": { 264 | "_objectId": "_objectId_qyfACNGb", 265 | "clsName": "UIDevice" 266 | }, 267 | "method": "currentDevice" 268 | }, { 269 | "returnVar": { 270 | "_objectId": "_objectId_haPktBlL" 271 | }, 272 | "object": { 273 | "_objectId": "_objectId_KNWtiPuM" 274 | }, 275 | "method": "systemVersion" 276 | }, { 277 | "object": { 278 | "_objectId": "_objectId_UAUcgnOD", 279 | "clsName": "NSString" 280 | }, 281 | "method": "stringWithString:", 282 | "args": ["iOS-"], 283 | "returnVar": { 284 | "_objectId": "_objectId_UiCMaHAN" 285 | } 286 | }, { 287 | "object": { 288 | "_objectId": "_objectId_UiCMaHAN" 289 | }, 290 | "method": "stringByAppendingString:", 291 | "args": [{ 292 | "_objectId": "_objectId_haPktBlL" 293 | }], 294 | "returnVar": { 295 | "_objectId": "_objectId_WyWRIsLl" 296 | } 297 | }] 298 | } 299 | ``` 300 | 我们在 `Native` 维护了一个 `objectsInContextMap` , `以objectId` 为键,以 `Native对象` 为值。 301 | 302 | `_invocationNodes` 便是方法的调用上下文, 看单个 303 | 304 | 这里会动态调用 `[UIDevice currentDevice]`, 返回对象以 `returnVar中存储的"_objectId_KNWtiPuM" ` 为键放到 `objectsInContextMap` 里 305 | 306 | ``` 307 | { 308 | "returnVar": { 309 | "_objectId": "_objectId_KNWtiPuM" 310 | }, 311 | "object": { 312 | "_objectId": "_objectId_qyfACNGb", 313 | "clsName": "UIDevice" 314 | }, 315 | "method": "currentDevice" 316 | }, 317 | ``` 318 | 319 | 这里 `调用方法的对象的objectId` 是 `"_objectId_KNWtiPuM"` ,是上一个方法的返回值,从`objectsInContextMap` 中取出,继续动态调用,以 `returnVar的object_id为键` 存储新的返回值。 320 | 321 | ``` 322 | { 323 | "returnVar": { 324 | "_objectId": "_objectId_haPktBlL" 325 | }, 326 | "object": { 327 | "_objectId": "_objectId_KNWtiPuM" // 会在objectsInContextMap找到中真正的对象 328 | }, 329 | "method": "systemVersion" 330 | } 331 | ``` 332 | 方法有参数时,支持自动装包和解包的,如 `int<->NSNumber..`, 如果参数是非 `channel` 规定的15种基本类型,是`NativeObject`, 我们会把对象从 `objectsInContextMap ` 中找出,放到实际的参数列表里 333 | 334 | ``` 335 | { 336 | "object": { 337 | "_objectId": "_objectId_UiCMaHAN" 338 | }, 339 | "method": "stringByAppendingString:", 340 | "args": [{ 341 | "_objectId": "_objectId_haPktBlL" // 会在objectsInContextMap找到中真正的对象 342 | }], 343 | "returnVar": { 344 | "_objectId": "_objectId_WyWRIsLl" 345 | } 346 | ``` 347 | ... 348 | 349 | 如果设置了`最终的returnVar`, 将把该 `returnVar objectId` 对应的对象从 `objectsInContextMap` 中找出来,作为 `channel的返回值` 回调回去。如果没有设置,取最后一个 `invocation` 的返回值(如果有)。 350 | 351 | ## 作者 352 | zyd178591@alibaba-inc.com, zhengguang.zzg@alibaba-inc.com, yongguang.lyg@alibaba-inc.com 353 | 354 | ## 更新日志 355 | | version | note | 356 | | ------ | ------ | 357 | | 0.1.0 | 能用 | 358 | 359 | ## License 360 | 361 | dna is available under the MIT license. See the LICENSE file for more info. 362 | 363 | ## 其他 364 | 365 | * 代码仓库近期会迁移到eleme下 366 | * 欢迎试用,建议和提交代码 367 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | /.idea 8 | /gradle 9 | gradlew 10 | gradlew.bat 11 | .gradlew/ -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'me.ele.dna' 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.2.1' 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 28 26 | 27 | defaultConfig { 28 | minSdkVersion 16 29 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 30 | } 31 | lintOptions { 32 | disable 'InvalidPackage' 33 | } 34 | } 35 | 36 | dependencies { 37 | implementation "com.google.code.gson:gson:2.8.5" 38 | implementation 'me.ele:dna-annotations:1.2.0' 39 | annotationProcessor 'me.ele:dna-compiler:1.2.0' 40 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'dna' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/DLog.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Author: Zhiqing.Zhang 7 | * FileName: DLog 8 | * Description: dna log utls 9 | */ 10 | 11 | public class DLog { 12 | 13 | public static final String DNA = "dna"; 14 | 15 | public static void e(String msg) { 16 | Log.e(DNA, msg); 17 | } 18 | 19 | public static void i(String msg) { 20 | Log.i(DNA, msg); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/DnaClient.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna; 2 | 3 | import android.text.TextUtils; 4 | 5 | import me.ele.dna.exception.AbnormalConstructorException; 6 | import me.ele.dna.exception.AbnormalMethodException; 7 | import me.ele.dna.exception.ArgsException; 8 | import me.ele.dna.finder.ConstructorFinder; 9 | import me.ele.dna.finder.BaseDnaFinder; 10 | import me.ele.dna.finder.MethodFinder; 11 | import me.ele.dna.finder.ProxyFinder; 12 | import me.ele.dna.model.MethodInfo; 13 | import me.ele.dna.model.MethodTacker; 14 | import me.ele.dna.model.ParameterInfo; 15 | import me.ele.dna.model.ResultInfo; 16 | import me.ele.dna.util.DnaUtils; 17 | import me.ele.dna_annotations.DnaConstants; 18 | 19 | import java.lang.reflect.Constructor; 20 | import java.lang.reflect.InvocationTargetException; 21 | import java.lang.reflect.Method; 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | 28 | /** 29 | * Author: Zhiqing.Zhang 30 | * FileName: DnaClient 31 | * Description: 32 | */ 33 | 34 | public class DnaClient { 35 | private IResultCallBack iResultCallBack; 36 | 37 | private static Map> classCahe = new HashMap<>(); 38 | 39 | private static Map> classConstructiorCahe = new HashMap<>(); 40 | 41 | private static Map> methodCache = new HashMap<>(); 42 | 43 | private static DnaClient mInstance; 44 | 45 | public static DnaClient getClient() { 46 | if (mInstance == null) { 47 | synchronized (DnaClient.class) { 48 | if (mInstance == null) { 49 | mInstance = new DnaClient(); 50 | } 51 | } 52 | } 53 | return mInstance; 54 | } 55 | 56 | public DnaClient() { 57 | 58 | } 59 | 60 | public void setiResultCallBack(IResultCallBack iResultCallBack) { 61 | this.iResultCallBack = iResultCallBack; 62 | } 63 | 64 | public IResultCallBack getiResultCallBack() { 65 | return iResultCallBack; 66 | } 67 | 68 | /** 69 | * 调用构造方法 70 | * 71 | * @param className 72 | * @param param 73 | * @return 74 | * @throws ClassNotFoundException 75 | * @throws IllegalAccessException 76 | */ 77 | public ResultInfo invokeConstructorMethod(String className, List param) 78 | throws ClassNotFoundException, ArgsException, AbnormalMethodException, IllegalAccessException, InstantiationException, AbnormalConstructorException, InvocationTargetException { 79 | boolean isProxy = false; 80 | if (!TextUtils.isEmpty(className) && (className.startsWith("android.") || className.startsWith("java."))) { 81 | try { 82 | Class.forName(className); 83 | } catch (ClassNotFoundException e) { 84 | isProxy = true; 85 | } 86 | } else { 87 | isProxy = true; 88 | } 89 | if (isProxy) { 90 | String methodName = DnaConstants.PROXYCONSTRUCTOR.concat(className.substring(className.lastIndexOf(".") + 1)); 91 | return invokeMethod(true, className, null, methodName, param); 92 | } 93 | return invokeRawConstructorMethod(className, param); 94 | } 95 | 96 | public ResultInfo invokeRawConstructorMethod(String className, List param) 97 | throws ClassNotFoundException, InstantiationException, IllegalAccessException, AbnormalConstructorException, InvocationTargetException { 98 | Class constructorClass = classConstructiorCahe.get(className); 99 | if (constructorClass == null) { 100 | constructorClass = Class.forName(className); 101 | classConstructiorCahe.put(className, constructorClass); 102 | } 103 | 104 | if (DnaUtils.isEmpty(param)) { 105 | return new ResultInfo(constructorClass.newInstance(), className); 106 | } 107 | 108 | return new ResultInfo(constructorOwner(constructorClass, param), className); 109 | } 110 | 111 | /** 112 | * 调用方法 113 | * 114 | * @param className 115 | * @param owner 116 | * @param methodName 117 | * @param param 118 | * @return 119 | * @throws ArgsException 120 | * @throws ClassNotFoundException 121 | * @throws AbnormalMethodException 122 | */ 123 | public ResultInfo invokeMethod(boolean isConstruct, String className, Object owner, String methodName, List param) throws ArgsException, ClassNotFoundException, AbnormalMethodException { 124 | Map methods = methodCache.get(className); 125 | MethodInfo methodImp = null; 126 | if (methods == null) { 127 | methods = new HashMap<>(); 128 | } 129 | if (!methods.isEmpty()) { 130 | methodImp = methods.get(methodName); 131 | } 132 | if (methodImp == null || !methodImp.checkParam(param)) { 133 | methodImp = getReflectMethod(isConstruct, className, methodName, param); 134 | methods.put(methodName, methodImp); 135 | } 136 | if (methodImp == null) { 137 | throw new AbnormalMethodException("method exception"); 138 | } 139 | MethodTacker methodTacker = new MethodTacker(methodImp); 140 | List args = methodTacker.getArgs(param, owner); 141 | Object returnResult = reflectMethod(methodImp.getMethod(), methodImp.isProxy() ? null : owner, args != null ? args.toArray() : null); 142 | return new ResultInfo(returnResult, methodImp.getReturnType()); 143 | } 144 | 145 | private MethodInfo getReflectMethod(boolean isConstruct, String className, String methodName, List param) throws ClassNotFoundException { 146 | boolean isProxy = false; 147 | Class invokeClass = classCahe.get(className); 148 | if (invokeClass == null) { 149 | if (!TextUtils.isEmpty(className) && (className.startsWith("android.") || className.startsWith("java."))) { 150 | try { 151 | invokeClass = Class.forName(className); 152 | } catch (ClassNotFoundException e) { 153 | isProxy = true; 154 | } 155 | } else { 156 | isProxy = true; 157 | } 158 | if (isProxy) { 159 | methodName = isConstruct ? methodName : className.substring(className.lastIndexOf(".") + 1) + "_" + methodName; 160 | className = className.substring(0, className.lastIndexOf(".") + 1) + DnaConstants.PROXYCLASS; 161 | invokeClass = Class.forName(className); 162 | } 163 | classCahe.put(className, invokeClass); 164 | } 165 | BaseDnaFinder finder = isProxy ? ProxyFinder.build(invokeClass, methodName, param, isConstruct) : MethodFinder.build(invokeClass, methodName, param, isConstruct); 166 | return finder.getReflectMethodFromClazz(); 167 | } 168 | 169 | /** 170 | * 构造函数 171 | * 172 | * @param param 173 | */ 174 | private Object constructorOwner(Class owner, List param) throws InstantiationException, IllegalAccessException, AbnormalConstructorException, 175 | IllegalArgumentException, InvocationTargetException { 176 | Constructor[] cons = owner.getConstructors(); 177 | if (cons == null || cons.length == 0) { 178 | return null; 179 | } 180 | Object ownerInstance; 181 | ConstructorFinder constructorFinder = new ConstructorFinder(owner, param); 182 | Constructor con = constructorFinder.getConstructor(); 183 | if (con == null) { 184 | throw new AbnormalConstructorException("invalid constructor"); 185 | } else { 186 | ownerInstance = con.newInstance(getParamContent(param).toArray()); 187 | } 188 | return ownerInstance; 189 | 190 | } 191 | 192 | private Object reflectMethod(Method method, Object owner, Object... args) { 193 | try { 194 | return method.invoke(owner, (args == null || args.length == 0) ? null : args); 195 | } catch (InvocationTargetException e) { 196 | DLog.i(e.getMessage()); 197 | } catch (IllegalAccessException e) { 198 | throw new IllegalStateException("Unexpected exception", e); 199 | } 200 | return null; 201 | } 202 | 203 | private List getParamContent(List parameterInfos) { 204 | if (DnaUtils.isEmpty(parameterInfos)) { 205 | return null; 206 | } 207 | List list = new ArrayList<>(); 208 | for (ParameterInfo info : parameterInfos) { 209 | list.add(info.getContent()); 210 | } 211 | return list; 212 | } 213 | 214 | } 215 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/DnaPlugin.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna; 2 | 3 | import me.ele.dna.model.DnaClassInfo; 4 | import me.ele.dna.model.ParameterInfo; 5 | import me.ele.dna.model.ResultInfo; 6 | import me.ele.dna.util.DnaUtils; 7 | import me.ele.dna.util.GsonUtils; 8 | 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import io.flutter.plugin.common.MethodCall; 15 | import io.flutter.plugin.common.MethodChannel; 16 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 17 | import io.flutter.plugin.common.MethodChannel.Result; 18 | import io.flutter.plugin.common.PluginRegistry.Registrar; 19 | 20 | /** 21 | * DnaPlugin 22 | */ 23 | public class DnaPlugin implements MethodCallHandler { 24 | 25 | public static final String EXECUTE_NATIVE_CONTEXT = "executeNativeContext"; 26 | public static final String INVOCATION_NODES = "_invocationNodes"; 27 | public static final String OBJECT_JSON_WRAPPERS = "_objectJSONWrappers"; 28 | public static final String RETURN_VAR = "returnVar"; 29 | public static final String OBJECT_ID = "_objectId"; 30 | public static final String DNA_JSON = "json"; 31 | public static final String DNA_CLS = "cls"; 32 | public static final String DNA_OBJECT = "object"; 33 | public static final String DNA_CLS_NAME = "clsName"; 34 | public static final String DNA_METHOD = "method"; 35 | public static final String DNA_ARGS = "args"; 36 | public static final String DNA_CONSTRUCT_CLS = "constructCls"; 37 | 38 | /** 39 | * Plugin registration. 40 | */ 41 | public static void registerWith(Registrar registrar) { 42 | final MethodChannel channel = new MethodChannel(registrar.messenger(), "dna"); 43 | channel.setMethodCallHandler(new DnaPlugin()); 44 | } 45 | 46 | @Override 47 | public void onMethodCall(MethodCall call, Result result) { 48 | if (call.method.equals("getPlatformVersion")) { 49 | result.success("Android " + android.os.Build.VERSION.RELEASE); 50 | } else if (call.method.equals(EXECUTE_NATIVE_CONTEXT)) { 51 | try { 52 | excuteNativeMethod(call, result); 53 | } catch (Exception e) { 54 | DLog.e(e.getMessage()); 55 | if (DnaClient.getClient().getiResultCallBack() != null) { 56 | DnaClient.getClient().getiResultCallBack().onException(e); 57 | } 58 | } 59 | } else { 60 | result.notImplemented(); 61 | } 62 | } 63 | 64 | private void excuteNativeMethod(MethodCall call, Result result) throws Exception { 65 | List> invocationNodes = call.argument(INVOCATION_NODES); 66 | List> objectJSONs = call.argument(OBJECT_JSON_WRAPPERS); 67 | Map valueMap = new HashMap<>();// 用于映射id和返回值 68 | if (DnaUtils.isEmpty(invocationNodes)) { 69 | return; 70 | } 71 | Map returnVar = call.argument(RETURN_VAR); 72 | String finalReturnVarId = getReturnId(returnVar); 73 | if (!DnaUtils.isEmpty(objectJSONs)) { 74 | for (Map objectJson : objectJSONs) { 75 | String objectId = String.valueOf(objectJson.get(OBJECT_ID)); 76 | String content = GsonUtils.toJson(objectJson.get(DNA_JSON)); 77 | String classType = String.valueOf(objectJson.get(DNA_CLS)); 78 | valueMap.put(objectId, new ParameterInfo(content, classType)); 79 | } 80 | } 81 | 82 | Map idMap; 83 | String clsName; 84 | String constructName; 85 | String nodeId; 86 | String methodName; 87 | List argsMap; 88 | List parameterInfos; 89 | Object currentObject = null; 90 | for (Map node : invocationNodes) { 91 | idMap = (Map) node.get(DNA_OBJECT); 92 | nodeId = (String) idMap.get(OBJECT_ID); 93 | if (idMap.containsKey(DNA_CLS_NAME)) { 94 | clsName = (String) idMap.get(DNA_CLS_NAME); 95 | valueMap.put(nodeId, new DnaClassInfo(clsName, false)); 96 | } else if (!valueMap.containsKey(nodeId) && idMap.containsKey(DNA_CONSTRUCT_CLS)) { 97 | constructName = (String) idMap.get(DNA_CONSTRUCT_CLS); 98 | valueMap.put(nodeId, new DnaClassInfo(constructName, true)); 99 | } 100 | 101 | methodName = String.valueOf(node.get(DNA_METHOD)); 102 | argsMap = (List) node.get(DNA_ARGS); 103 | parameterInfos = getParameters(valueMap, argsMap); 104 | String returnId = getReturnId((Map) node.get(RETURN_VAR)); 105 | Object ownerObject = valueMap.get(nodeId); 106 | if (ownerObject == null) { 107 | return; 108 | } else if (ownerObject instanceof DnaClassInfo) { 109 | currentObject = ((DnaClassInfo) ownerObject).isConstrcut() 110 | ? DnaClient.getClient().invokeConstructorMethod(((DnaClassInfo) ownerObject).getClassName(), parameterInfos) 111 | : DnaClient.getClient().invokeMethod(false, ((DnaClassInfo) ownerObject).getClassName(), null, methodName, parameterInfos); 112 | } else if (ownerObject instanceof ResultInfo) { 113 | currentObject = DnaClient.getClient().invokeMethod(false, ((ResultInfo) ownerObject).getReturnType(), ((ResultInfo) ownerObject).getObject(), methodName, parameterInfos); 114 | } else { 115 | throw new Exception("Abnormal Error"); 116 | } 117 | valueMap.put(returnId, currentObject); 118 | if (returnId != null && returnId.equals(finalReturnVarId)) { 119 | Object o = valueMap.get(returnId); 120 | result.success(o instanceof ResultInfo ? ((ResultInfo) o).getObject() : o); 121 | } 122 | } 123 | result.success(currentObject instanceof ResultInfo ? ((ResultInfo) currentObject).getObject() : currentObject); 124 | 125 | } 126 | 127 | 128 | /** 129 | * 获取下一个节点的id 130 | * 131 | * @param returnVar 132 | * @return 133 | */ 134 | private String getReturnId(Map returnVar) { 135 | String returnVarId = null; 136 | if (returnVar != null && !returnVar.isEmpty()) { 137 | returnVarId = returnVar.get(OBJECT_ID); 138 | } 139 | return returnVarId; 140 | } 141 | 142 | /** 143 | * 获取参数信息 144 | * 145 | * @param valueMap 146 | * @param argsMap 147 | * @return 148 | */ 149 | private List getParameters(Map valueMap, List argsMap) { 150 | String paraId; 151 | Object paraContent; 152 | List parameters = new ArrayList<>(); 153 | if (!DnaUtils.isEmpty(argsMap)) { 154 | for (Object o : argsMap) { 155 | if (o instanceof Map) { 156 | paraId = String.valueOf(((Map) o).get(OBJECT_ID)); 157 | paraContent = valueMap.get(paraId); 158 | if (paraContent instanceof ParameterInfo) { 159 | parameters.add((ParameterInfo) paraContent); 160 | } else if (paraContent instanceof ResultInfo) { 161 | parameters.add(new ParameterInfo(getExcuteParameter(((ResultInfo) paraContent).getObject()), ((ResultInfo) paraContent).getReturnType())); 162 | } else if (paraContent != null) { 163 | parameters.add(new ParameterInfo(getExcuteParameter(paraContent), paraContent.getClass().getName())); 164 | } 165 | } else if (o != null) { 166 | parameters.add(new ParameterInfo(String.valueOf(o), o.getClass().getName())); 167 | 168 | } else { 169 | parameters.add(new ParameterInfo(null, null)); 170 | } 171 | } 172 | } 173 | return parameters; 174 | } 175 | 176 | private String getExcuteParameter(Object result) { 177 | return DnaUtils.isPrimitiveClass(result.getClass()) 178 | ? String.valueOf(result) 179 | : GsonUtils.toJson(result); 180 | } 181 | 182 | 183 | } 184 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/IResultCallBack.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna; 2 | 3 | public interface IResultCallBack { 4 | 5 | void onException(Exception e); 6 | } 7 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/exception/AbnormalConstructorException.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.exception; 2 | 3 | public class AbnormalConstructorException extends Exception { 4 | 5 | public AbnormalConstructorException(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/exception/AbnormalMethodException.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.exception; 2 | 3 | /** 4 | * Author: Zhiqing.Zhang 5 | * Description: 6 | */ 7 | public class AbnormalMethodException extends Exception { 8 | public AbnormalMethodException(String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/exception/ArgsException.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.exception; 2 | 3 | /** 4 | * Author: Zhiqing.Zhang 5 | * FileName: ArgsException 6 | * Description: 7 | */ 8 | 9 | public class ArgsException extends Exception { 10 | 11 | public ArgsException(String message) { 12 | super(message); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/finder/BaseDnaFinder.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.finder; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.lang.reflect.Method; 6 | import java.lang.reflect.Modifier; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | import me.ele.dna.model.MethodInfo; 12 | import me.ele.dna.util.DnaUtils; 13 | 14 | public abstract class BaseDnaFinder { 15 | protected static final int BRIDGE = 0x40; 16 | protected static final int SYNTHETIC = 0x1000; 17 | protected static final int MODIFIERS_UN = Modifier.ABSTRACT | BRIDGE | SYNTHETIC; 18 | 19 | protected Class invokeClass; 20 | 21 | protected String methodName; 22 | 23 | protected List paramType; 24 | 25 | protected boolean isConstruct; 26 | 27 | public BaseDnaFinder(Class invokeClass, String methodName, List paramType, boolean isConstruct) { 28 | this.invokeClass = invokeClass; 29 | this.methodName = methodName; 30 | this.paramType = paramType; 31 | this.isConstruct = isConstruct; 32 | } 33 | 34 | protected abstract MethodInfo getExactMethod(List methods); 35 | 36 | public MethodInfo getReflectMethodFromClazz() { 37 | List tempMethodList = new ArrayList<>(); 38 | Method[] methods = invokeClass.getMethods(); 39 | if (methods == null) { 40 | return null; 41 | } 42 | for (Method method : methods) { 43 | int modifier = method.getModifiers(); 44 | if ((modifier & Modifier.PUBLIC) != 0 && (modifier & MODIFIERS_UN) == 0) { 45 | if (methodName.equals(method.getName())) { 46 | tempMethodList.add(method); 47 | } 48 | } 49 | } 50 | return getExactMethod(tempMethodList); 51 | } 52 | 53 | protected MethodInfo createMethod(Method method, String returnType) { 54 | MethodInfo methodInfo = null; 55 | if (method != null) { 56 | Class[] parameterTypes = method.getParameterTypes(); 57 | methodInfo = new MethodInfo(method, Arrays.asList(parameterTypes), returnType, this instanceof ProxyFinder, isConstruct); 58 | } 59 | return methodInfo; 60 | } 61 | 62 | /** 63 | * java.lang.Boolean#TYPE 64 | * java.lang.Character#TYPE 65 | * java.lang.Byte#TYPE 66 | * java.lang.Short#TYPE 67 | * java.lang.Integer#TYPE 68 | * java.lang.Long#TYPE 69 | * java.lang.Float#TYPE 70 | * java.lang.Double#TYPE 71 | * java.lang.Void#TYPE 72 | * 73 | * @param name 74 | * @return 75 | */ 76 | protected String wrapper(String name) { 77 | switch (name) { 78 | case "boolean": 79 | return Boolean.class.getName(); 80 | case "char": 81 | return Character.class.getName(); 82 | case "byte": 83 | return Byte.class.getName(); 84 | case "short": 85 | return Short.class.getName(); 86 | case "int": 87 | return Integer.class.getName(); 88 | case "long": 89 | return Long.class.getName(); 90 | case "float": 91 | return Float.class.getName(); 92 | case "double": 93 | return Double.class.getName(); 94 | case "void": 95 | return Void.class.getName(); 96 | default: 97 | return null; 98 | } 99 | } 100 | 101 | protected boolean isEqualType(String dartType, String javaType) { 102 | if (TextUtils.isEmpty(dartType) && TextUtils.isEmpty(javaType)) { 103 | return true; 104 | } 105 | 106 | if (TextUtils.isEmpty(dartType) || TextUtils.isEmpty(javaType)) { 107 | return false; 108 | } 109 | if (javaType.equals(Float.class.getName()) && dartType.equals(Double.class.getName())) { 110 | return true; 111 | } 112 | if (javaType.equals(Long.class.getName()) && dartType.equals(Integer.class.getName())) { 113 | return true; 114 | } 115 | if (javaType.equals(Short.class.getName()) && dartType.equals(Integer.class.getName())) { 116 | return true; 117 | } 118 | return javaType.equals(dartType); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/finder/ConstructorFinder.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.finder; 2 | 3 | import me.ele.dna.model.ParameterInfo; 4 | import me.ele.dna.util.DnaUtils; 5 | 6 | import java.lang.reflect.Constructor; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * Author: Zhiqing.Zhang 12 | * Description: 13 | */ 14 | public class ConstructorFinder { 15 | 16 | Class owner; 17 | 18 | List param; 19 | 20 | public ConstructorFinder(Class owner, List param) { 21 | this.owner = owner; 22 | this.param = new ArrayList<>(); 23 | if (!DnaUtils.isEmpty(param)) { 24 | for (ParameterInfo info : param) { 25 | this.param.add(info.getType()); 26 | } 27 | } 28 | } 29 | 30 | public Constructor getConstructor() { 31 | if (owner == null) { 32 | return null; 33 | } 34 | Constructor[] cons = owner.getConstructors(); 35 | if (cons == null || cons.length == 0) { 36 | return null; 37 | } 38 | for (Constructor con : cons) { 39 | if (checkConstructor(con, param)) { 40 | return con; 41 | } 42 | } 43 | return null; 44 | } 45 | 46 | private boolean checkConstructor(Constructor con, List param) { 47 | Class[] parameterTypes = con.getParameterTypes(); 48 | if (parameterTypes.length != param.size()) { 49 | return false; 50 | } 51 | if (parameterTypes.length == 0) { 52 | return true; 53 | } 54 | for (int i = 0; i < parameterTypes.length; i++) { 55 | if (parameterTypes[i].getName() != param.get(i) && param.get(i) != null) { 56 | return false; 57 | } 58 | } 59 | return true; 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/finder/MethodFinder.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.finder; 2 | 3 | import me.ele.dna.model.MethodInfo; 4 | import me.ele.dna.model.ParameterInfo; 5 | import me.ele.dna.util.DnaUtils; 6 | 7 | import java.lang.reflect.Method; 8 | import java.lang.reflect.Type; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * Author: Zhiqing.Zhang 14 | * Description: 15 | */ 16 | public class MethodFinder extends BaseDnaFinder { 17 | 18 | public static MethodFinder build(Class invokeClass, String methodName, List paramInfoList, boolean isConstruct) { 19 | List paramType = new ArrayList<>(); 20 | if (!DnaUtils.isEmpty(paramInfoList)) { 21 | for (ParameterInfo info : paramInfoList) { 22 | paramType.add(info.getType()); 23 | 24 | } 25 | } 26 | return new MethodFinder(invokeClass, methodName, paramType, isConstruct); 27 | } 28 | 29 | public MethodFinder(Class invokeClass, String methodName, List paramType, boolean isConstruct) { 30 | super(invokeClass, methodName, paramType, isConstruct); 31 | } 32 | 33 | @Override 34 | protected MethodInfo getExactMethod(List methods) { 35 | if (DnaUtils.isEmpty(methods)) { 36 | return null; 37 | } 38 | boolean isExactMethod; 39 | Method curMethod = null; 40 | for (Method method : methods) { 41 | Type[] types = method.getGenericParameterTypes(); 42 | if (types == null && paramType == null) { 43 | curMethod = method; 44 | break; 45 | } 46 | if (types == null || paramType == null || types.length != paramType.size()) { 47 | continue; 48 | } 49 | if (types.length == 0) { 50 | curMethod = method; 51 | break; 52 | } 53 | isExactMethod = true; 54 | for (int i = 0; i < types.length; i++) { 55 | if (!(types[i] instanceof Class)) { 56 | return null; 57 | } 58 | if (paramType.get(i) != null) { 59 | String typeName = ((Class) types[i]).isPrimitive() 60 | ? wrapper(((Class) types[i]).getName()) 61 | : ((Class) types[i]).getName(); 62 | if (!(isEqualType(paramType.get(i), typeName))) { 63 | isExactMethod = false; 64 | break; 65 | } 66 | } 67 | } 68 | if (isExactMethod) { 69 | curMethod = method; 70 | break; 71 | } 72 | } 73 | return curMethod != null ? createMethod(curMethod, curMethod.getReturnType().getName()) : null; 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/finder/ProxyFinder.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.finder; 2 | 3 | 4 | import java.lang.reflect.Method; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import me.ele.dna.model.MethodInfo; 9 | import me.ele.dna.model.ParameterInfo; 10 | import me.ele.dna.util.DnaUtils; 11 | import me.ele.dna_annotations.DnaParamFieldList; 12 | 13 | public class ProxyFinder extends BaseDnaFinder { 14 | 15 | public static ProxyFinder build(Class invokeClass, String methodName, List paramInfoList, boolean isConstruct) { 16 | List paramType = new ArrayList<>(); 17 | if (!DnaUtils.isEmpty(paramInfoList)) { 18 | for (ParameterInfo info : paramInfoList) { 19 | paramType.add(info.getType()); 20 | 21 | } 22 | } 23 | return new ProxyFinder(invokeClass, methodName, paramType, isConstruct); 24 | } 25 | 26 | public ProxyFinder(Class invokeClass, String methodName, List paramType, boolean isConstruct) { 27 | super(invokeClass, methodName, paramType, isConstruct); 28 | } 29 | 30 | @Override 31 | protected MethodInfo getExactMethod(List methods) { 32 | if (DnaUtils.isEmpty(methods)) { 33 | return null; 34 | } 35 | boolean isExactMethod; 36 | String[] params; 37 | String returnType; 38 | for (Method method : methods) { 39 | DnaParamFieldList fieldList = method.getAnnotation(DnaParamFieldList.class); 40 | if (fieldList == null) { 41 | continue; 42 | } 43 | params = fieldList.params(); 44 | returnType = fieldList.returnType(); 45 | if (paramType == null || params.length != paramType.size()) { 46 | continue; 47 | } 48 | if (params.length == 0) { 49 | return createMethod(method, returnType); 50 | } 51 | isExactMethod = true; 52 | for (int i = 0; i < params.length; i++) { 53 | if (paramType.get(i) != null) { 54 | String typeName = wrapper(params[i]) != null ? wrapper(params[i]) : params[i]; 55 | if (!isEqualType(paramType.get(i), typeName)) { 56 | isExactMethod = false; 57 | break; 58 | } 59 | } 60 | } 61 | if (isExactMethod) { 62 | return createMethod(method, returnType); 63 | } 64 | } 65 | return null; 66 | } 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/model/DnaClassInfo.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Author: ZhiQing.Zhang 7 | **/ 8 | public class DnaClassInfo { 9 | String className; 10 | 11 | boolean isConstrcut; 12 | 13 | List args; 14 | 15 | public DnaClassInfo(String className, boolean isConstrcut) { 16 | this.className = className; 17 | this.isConstrcut = isConstrcut; 18 | } 19 | 20 | 21 | public String getClassName() { 22 | return className; 23 | } 24 | 25 | public void setClassName(String className) { 26 | this.className = className; 27 | } 28 | 29 | public boolean isConstrcut() { 30 | return isConstrcut; 31 | } 32 | 33 | public void setConstrcut(boolean constrcut) { 34 | isConstrcut = constrcut; 35 | } 36 | 37 | public List getArgs() { 38 | return args; 39 | } 40 | 41 | public void setArgs(List args) { 42 | this.args = args; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/model/DnaResult.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.model; 2 | 3 | public class DnaResult { 4 | 5 | Object content; 6 | 7 | String varId; 8 | 9 | public DnaResult(Object content, String varId) { 10 | this.content = content; 11 | this.varId = varId; 12 | } 13 | 14 | public Object getContent() { 15 | return content; 16 | } 17 | 18 | public void setContent(Object content) { 19 | this.content = content; 20 | } 21 | 22 | public String getVarId() { 23 | return varId; 24 | } 25 | 26 | public void setVarId(String varId) { 27 | this.varId = varId; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/model/MethodInfo.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.model; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.List; 5 | 6 | /** 7 | * Author: Zhiqing.Zhang 8 | * FileName: MethodInfo 9 | * Description: 10 | */ 11 | 12 | public class MethodInfo { 13 | 14 | private Method method; 15 | 16 | private List> args; 17 | 18 | private String returnType; 19 | 20 | private boolean isProxy; 21 | 22 | private boolean isConstruct; 23 | 24 | 25 | public MethodInfo(Method method, List> args, String returnType, boolean isProxy, boolean isConstruct) { 26 | this.method = method; 27 | this.args = args; 28 | this.returnType = returnType; 29 | this.isProxy = isProxy; 30 | this.isConstruct = isConstruct; 31 | } 32 | 33 | public String getReturnType() { 34 | return returnType; 35 | } 36 | 37 | public Method getMethod() { 38 | return method; 39 | } 40 | 41 | public void setMethod(Method method) { 42 | this.method = method; 43 | } 44 | 45 | public List> getArgs() { 46 | return args; 47 | } 48 | 49 | public boolean isProxy() { 50 | return isProxy; 51 | } 52 | 53 | public boolean isConstruct() { 54 | return isConstruct; 55 | } 56 | 57 | public void setArgs(List> args) { 58 | this.args = args; 59 | } 60 | 61 | public boolean checkParam(List parameterInfos) { 62 | if (args == null && parameterInfos == null) { 63 | return true; 64 | } 65 | if (args == null 66 | || parameterInfos == null 67 | || args.size() != parameterInfos.size()) { 68 | return false; 69 | } 70 | for (int i = 0; i < args.size(); i++) { 71 | if (args.get(i).getName() != parameterInfos.get(i).getType()) { 72 | return false; 73 | } 74 | } 75 | return true; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/model/MethodTacker.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.model; 2 | 3 | import me.ele.dna.util.GsonUtils; 4 | import me.ele.dna.exception.ArgsException; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import me.ele.dna.exception.ArgsException; 10 | 11 | 12 | /** 13 | * Author: Zhiqing.Zhang 14 | * FileName: MethodTacker 15 | * Description: 16 | */ 17 | 18 | public class MethodTacker { 19 | MethodInfo info; 20 | 21 | public MethodTacker(MethodInfo info) { 22 | this.info = info; 23 | } 24 | 25 | public List getArgs(List args, Object owner) throws ArgsException { 26 | if (info == null) { 27 | return null; 28 | } 29 | List> reflectArgs = info.getArgs(); 30 | if (reflectArgs == null || args == null) { 31 | return null; 32 | } 33 | if (info.isProxy() && !info.isConstruct() && reflectArgs.size() != args.size() + 1) { 34 | throw new ArgsException("proxy class Args size error"); 35 | 36 | } 37 | if (!info.isProxy() && reflectArgs.size() != args.size()) { 38 | throw new ArgsException("Args size error"); 39 | } 40 | List argsElements = new ArrayList<>(); 41 | if (info.isProxy() && !info.isConstruct()) { 42 | argsElements.add(0, owner); 43 | for (int i = 1; i < reflectArgs.size(); i++) { 44 | argsElements.add(isString(reflectArgs.get(i)) ? args.get(i - 1).getContent() : GsonUtils.fromJson(args.get(i - 1).getContent(), reflectArgs.get(i))); 45 | } 46 | } else { 47 | for (int i = 0; i < reflectArgs.size(); i++) { 48 | argsElements.add(isString(reflectArgs.get(i)) ? args.get(i).getContent() : GsonUtils.fromJson(args.get(i).getContent(), reflectArgs.get(i))); 49 | } 50 | } 51 | 52 | return argsElements; 53 | } 54 | 55 | public static boolean isString(Class clz) { 56 | if (clz.getName().equals(String.class.getName())) { 57 | return true; 58 | } 59 | return false; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/model/ParameterInfo.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.model; 2 | 3 | /** 4 | * Author: Zhiqing.Zhang 5 | * Description: 6 | */ 7 | public class ParameterInfo { 8 | String content; 9 | 10 | String type; 11 | 12 | public ParameterInfo(String content, String type) { 13 | this.content = content; 14 | this.type = type; 15 | } 16 | 17 | public String getContent() { 18 | return content; 19 | } 20 | 21 | public void setContent(String content) { 22 | this.content = content; 23 | } 24 | 25 | public String getType() { 26 | return type; 27 | } 28 | 29 | public void setType(String type) { 30 | this.type = type; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/model/ResultInfo.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.model; 2 | 3 | public class ResultInfo { 4 | Object object; 5 | 6 | String returnType; 7 | 8 | public ResultInfo(Object object, String returnType) { 9 | this.object = object; 10 | this.returnType = returnType; 11 | } 12 | 13 | public Object getObject() { 14 | return object; 15 | } 16 | 17 | public String getReturnType() { 18 | return returnType; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/util/DnaUtils.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.util; 2 | 3 | 4 | import java.util.Collection; 5 | /** 6 | * Author: Zhiqing.Zhang 7 | * Description: 8 | */ 9 | public class DnaUtils { 10 | 11 | public static boolean isEmpty(Collection collection) { 12 | return collection == null || collection.isEmpty(); 13 | } 14 | 15 | 16 | public static boolean isPrimitiveClass(Class clz) { 17 | if (clz.getName() == String.class.getName()) { 18 | return true; 19 | } 20 | return clz.isPrimitive() || isWrapClass(clz); 21 | } 22 | 23 | public static boolean isWrapClass(Class clz) { 24 | try { 25 | return ((Class) clz.getField("TYPE").get(null)).isPrimitive(); 26 | } catch (Exception e) { 27 | return false; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /android/src/main/java/me/ele/dna/util/GsonUtils.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna.util; 2 | 3 | import com.google.gson.Gson; 4 | 5 | import java.lang.reflect.Type; 6 | 7 | /** 8 | * Author: Zhiqing.Zhang 9 | * FileName: GsonUtils 10 | * Description: 11 | */ 12 | 13 | public class GsonUtils { 14 | private static final Gson GSON = new Gson(); 15 | 16 | private GsonUtils() { 17 | } 18 | 19 | public static String toJson(Object obj) { 20 | return null == obj ? "" : GSON.toJson(obj); 21 | } 22 | 23 | public static Object fromJson(String json, Type classType) { 24 | return null == json ? null : GSON.fromJson(json, classType); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /dna.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # Exceptions to above rules. 66 | !**/ios/**/default.mode1v3 67 | !**/ios/**/default.mode2v3 68 | !**/ios/**/default.pbxuser 69 | !**/ios/**/default.perspectivev3 70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 71 | -------------------------------------------------------------------------------- /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: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /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 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 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 "me.ele.dna_example" 37 | minSdkVersion 16 38 | targetSdkVersion 28 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 | minifyEnabled true 50 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 51 | } 52 | 53 | debug { 54 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 55 | } 56 | } 57 | } 58 | 59 | flutter { 60 | source '../..' 61 | } 62 | 63 | dependencies { 64 | testImplementation 'junit:junit:4.12' 65 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 66 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 67 | implementation 'com.google.code.gson:gson:2.8.5' 68 | implementation 'me.ele:dna-annotations:1.2.0' 69 | annotationProcessor 'me.ele:dna-compiler:1.2.0' 70 | 71 | } 72 | -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | 2 | -ignorewarnings 3 | 4 | -keep class **.Dna_Class_Proxy { *; } 5 | 6 | -keep class io.flutter.app.** { *; } 7 | -keep class io.flutter.plugin.** { *; } 8 | -keep class io.flutter.util.** { *; } 9 | -keep class io.flutter.view.** { *; } 10 | -keep class io.flutter.** { *; } 11 | -keep class io.flutter.plugins.** { *; } 12 | -keep class me.ele.dna_compiler.** { *; } 13 | -keep class me.ele.dna.** { *; } -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/me/ele/dna_example/DnaTest.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_example; 2 | 3 | 4 | 5 | import me.ele.dna_annotations.DnaMethod; 6 | 7 | 8 | public class DnaTest { 9 | 10 | @DnaMethod 11 | public DnaTest() { 12 | } 13 | 14 | @DnaMethod 15 | public DnaVersion getDnaVersion() { 16 | return new DnaVersion(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/me/ele/dna_example/DnaVersion.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_example; 2 | 3 | 4 | import me.ele.dna_annotations.DnaMethod; 5 | 6 | public class DnaVersion { 7 | 8 | @DnaMethod 9 | public DnaVersion() { 10 | } 11 | 12 | @DnaMethod 13 | public String getVersion() { 14 | return android.os.Build.VERSION.RELEASE; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/me/ele/dna_example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_example; 2 | 3 | import android.os.Bundle; 4 | import android.util.Log; 5 | 6 | import io.flutter.app.FlutterActivity; 7 | import io.flutter.plugins.GeneratedPluginRegistrant; 8 | import me.ele.dna.DnaClient; 9 | 10 | public class MainActivity extends FlutterActivity { 11 | public static String TAG = "DNA"; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | GeneratedPluginRegistrant.registerWith(this); 17 | DnaClient.getClient().setiResultCallBack(e -> { 18 | Log.i(TAG, "error msg:" + e.getMessage()); 19 | }); 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.1' 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/dna-annotations/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /example/android/dna-annotations/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | 3 | dependencies { 4 | implementation fileTree(dir: 'libs', include: ['*.jar']) 5 | } 6 | 7 | sourceCompatibility = "1.8" 8 | targetCompatibility = "1.8" 9 | -------------------------------------------------------------------------------- /example/android/dna-annotations/src/main/java/me/ele/dna_annotations/DnaConstants.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_annotations; 2 | 3 | public class DnaConstants { 4 | public static final String PROXYCLASS = "Dna_Class_Proxy"; 5 | public static final String PROXYCONSTRUCTOR = "Dna_Constructor_Proxy"; 6 | public static final String PROXYMETHOD = "Dna_Method_Proxy"; 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /example/android/dna-annotations/src/main/java/me/ele/dna_annotations/DnaMethod.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_annotations; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.Target; 5 | 6 | import static java.lang.annotation.ElementType.CONSTRUCTOR; 7 | import static java.lang.annotation.ElementType.METHOD; 8 | import static java.lang.annotation.RetentionPolicy.CLASS; 9 | 10 | @Target({METHOD, CONSTRUCTOR}) 11 | @Retention(CLASS) 12 | public @interface DnaMethod { 13 | } 14 | -------------------------------------------------------------------------------- /example/android/dna-annotations/src/main/java/me/ele/dna_annotations/DnaParamFieldList.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_annotations; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.Target; 5 | 6 | import static java.lang.annotation.ElementType.METHOD; 7 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 8 | 9 | @Target(METHOD) 10 | @Retention(RUNTIME) 11 | public @interface DnaParamFieldList { 12 | String owner(); 13 | 14 | String[] params(); 15 | 16 | String returnType(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /example/android/dna-compiler/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /example/android/dna-compiler/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | 3 | dependencies { 4 | implementation fileTree(dir: 'libs', include: ['*.jar']) 5 | implementation 'com.squareup:javapoet:1.12.1' 6 | implementation 'me.ele:dna-annotations:1.2.0' 7 | } 8 | 9 | sourceCompatibility = "1.8" 10 | targetCompatibility = "1.8" 11 | -------------------------------------------------------------------------------- /example/android/dna-compiler/src/main/java/me/ele/dna_compiler/BaseDnaElement.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_compiler; 2 | 3 | import com.squareup.javapoet.MethodSpec; 4 | 5 | import java.util.List; 6 | 7 | import javax.lang.model.element.TypeElement; 8 | 9 | public abstract class BaseDnaElement { 10 | protected List paramterType; 11 | protected TypeElement enclosingElement; 12 | protected String methodName; 13 | protected String returnType; 14 | 15 | public BaseDnaElement(List paramterType, TypeElement enclosingElement, String methodName, String returnType) { 16 | this.paramterType = paramterType; 17 | this.enclosingElement = enclosingElement; 18 | this.methodName = methodName; 19 | this.returnType = returnType; 20 | } 21 | 22 | public List getParamterType() { 23 | return paramterType; 24 | } 25 | 26 | public TypeElement getEnclosingElement() { 27 | return enclosingElement; 28 | } 29 | 30 | public String getMethodName() { 31 | return methodName; 32 | } 33 | 34 | public abstract MethodSpec createMethod(); 35 | 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /example/android/dna-compiler/src/main/java/me/ele/dna_compiler/DnaClassFinder.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_compiler; 2 | 3 | import com.squareup.javapoet.JavaFile; 4 | import com.squareup.javapoet.TypeSpec; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | 10 | import static javax.lang.model.element.Modifier.PUBLIC; 11 | import static me.ele.dna_annotations.DnaConstants.PROXYCLASS; 12 | 13 | public class DnaClassFinder { 14 | private List methodInfos = new ArrayList<>(); 15 | 16 | private String packageName; 17 | 18 | public DnaClassFinder(String packageName) { 19 | this.packageName = packageName; 20 | } 21 | 22 | public void addMethodInfo(BaseDnaElement info) { 23 | if (methodInfos == null) { 24 | methodInfos = new ArrayList<>(); 25 | } 26 | methodInfos.add(info); 27 | } 28 | 29 | public String getPackageName() { 30 | return packageName; 31 | } 32 | 33 | public JavaFile createJavaFile() { 34 | TypeSpec.Builder classBuilder = TypeSpec.classBuilder(PROXYCLASS).addModifiers(PUBLIC); 35 | for (BaseDnaElement info : methodInfos) { 36 | classBuilder.addMethod(info.createMethod()); 37 | } 38 | 39 | return JavaFile.builder(packageName, classBuilder.build()) 40 | .addFileComment("Generated code from DNA Do not modify!") 41 | .build(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /example/android/dna-compiler/src/main/java/me/ele/dna_compiler/DnaConstructorInfo.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_compiler; 2 | 3 | import com.squareup.javapoet.AnnotationSpec; 4 | import com.squareup.javapoet.MethodSpec; 5 | import com.squareup.javapoet.TypeName; 6 | 7 | import java.util.List; 8 | 9 | import javax.lang.model.element.Modifier; 10 | import javax.lang.model.element.TypeElement; 11 | 12 | import me.ele.dna_annotations.DnaParamFieldList; 13 | 14 | public class DnaConstructorInfo extends BaseDnaElement { 15 | 16 | 17 | public DnaConstructorInfo(List paramterType, TypeElement enclosingElement, String methodName, String returnType) { 18 | super(paramterType, enclosingElement, methodName, returnType); 19 | } 20 | 21 | @Override 22 | public MethodSpec createMethod() { 23 | MethodSpec.Builder mehthodBuidler; 24 | mehthodBuidler = MethodSpec.methodBuilder(methodName). 25 | returns(TypeName.get(enclosingElement.asType())).addModifiers(Modifier.PUBLIC, Modifier.STATIC); 26 | String parament = ""; 27 | String annotionSpc = "{"; 28 | String[] annotionList = new String[]{}; 29 | int paramenterSize = 0; 30 | if (paramterType != null && paramterType.size() > 0) { 31 | paramenterSize = paramterType.size(); 32 | annotionList = new String[paramenterSize]; 33 | for (int i = 0; i < paramenterSize; i++) { 34 | mehthodBuidler.addParameter(paramterType.get(i).getTypeName(), "var" + i); 35 | annotionList[i] = paramterType.get(i).getClassName(); 36 | if (i == paramterType.size() - 1) { 37 | parament += "$N"; 38 | annotionSpc += "$S"; 39 | } else { 40 | parament += "$N,"; 41 | annotionSpc += "$S,"; 42 | 43 | } 44 | } 45 | } 46 | parament += ")"; 47 | annotionSpc += "}"; 48 | String stateMement = "return new $N(" + parament; 49 | Object[] objects = new Object[paramenterSize + 1]; 50 | objects[0] = enclosingElement.getQualifiedName(); 51 | for (int i = 1; i < objects.length; i++) { 52 | objects[i] = "var" + (i - 1); 53 | } 54 | AnnotationSpec spec = AnnotationSpec.builder(DnaParamFieldList.class).addMember("params", annotionSpc, annotionList) 55 | .addMember("owner", "$S", "") 56 | .addMember("returnType", "$S", enclosingElement.getQualifiedName().toString()) 57 | .build(); 58 | mehthodBuidler.addStatement(stateMement, objects).addAnnotation(spec); 59 | return mehthodBuidler.build(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /example/android/dna-compiler/src/main/java/me/ele/dna_compiler/DnaMethodInfo.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_compiler; 2 | 3 | import com.squareup.javapoet.AnnotationSpec; 4 | import com.squareup.javapoet.MethodSpec; 5 | import com.squareup.javapoet.TypeName; 6 | 7 | import java.util.List; 8 | 9 | import javax.lang.model.element.Modifier; 10 | import javax.lang.model.element.TypeElement; 11 | 12 | import me.ele.dna_annotations.DnaParamFieldList; 13 | 14 | public class DnaMethodInfo extends BaseDnaElement { 15 | 16 | private boolean isReturn; 17 | 18 | public DnaMethodInfo(List paramterType, TypeElement enclosingElement, String methodName, boolean isReturn, String returnType) { 19 | super(paramterType, enclosingElement, methodName, returnType); 20 | this.isReturn = isReturn; 21 | } 22 | 23 | public String getClassName() { 24 | if (enclosingElement != null) { 25 | return enclosingElement.getSimpleName().toString(); 26 | 27 | } 28 | return ""; 29 | } 30 | 31 | public boolean isReturn() { 32 | return isReturn; 33 | } 34 | 35 | @Override 36 | public MethodSpec createMethod() { 37 | MethodSpec.Builder mehthodBuidler; 38 | mehthodBuidler = MethodSpec.methodBuilder(getClassName() + "_" + methodName).addModifiers(Modifier.PUBLIC, Modifier.STATIC). 39 | returns(isReturn ? Object.class : void.class); 40 | String parament = ""; 41 | String annotionSpc = "{"; 42 | String[] annotionList = new String[]{}; 43 | mehthodBuidler.addParameter( 44 | TypeName.get(enclosingElement.asType()), "owner"); 45 | int paramenterSize = 0; 46 | if (paramterType != null && paramterType.size() > 0) { 47 | paramenterSize = paramterType.size(); 48 | annotionList = new String[paramenterSize]; 49 | for (int i = 0; i < paramenterSize; i++) { 50 | mehthodBuidler.addParameter(paramterType.get(i).getTypeName(), "var" + i); 51 | annotionList[i] = paramterType.get(i).getClassName(); 52 | if (i == paramterType.size() - 1) { 53 | parament += "$N"; 54 | annotionSpc += "$S"; 55 | } else { 56 | parament += "$N,"; 57 | annotionSpc += "$S,"; 58 | 59 | } 60 | } 61 | } 62 | parament += ")"; 63 | annotionSpc += "}"; 64 | String stateMement; 65 | if (isReturn) { 66 | stateMement = "return $N.$N(" + parament; 67 | } else { 68 | stateMement = "$N.$N(" + parament; 69 | } 70 | Object[] objects = new Object[paramenterSize + 2]; 71 | objects[0] = "owner"; 72 | objects[1] = methodName; 73 | for (int i = 2; i < objects.length; i++) { 74 | objects[i] = "var" + (i - 2); 75 | } 76 | AnnotationSpec spec = AnnotationSpec.builder(DnaParamFieldList.class).addMember("params", annotionSpc, annotionList) 77 | .addMember("owner", "$S", enclosingElement.getQualifiedName().toString()) 78 | .addMember("returnType", "$S", returnType) 79 | .build(); 80 | mehthodBuidler.addStatement(stateMement, objects).addAnnotation(spec); 81 | return mehthodBuidler.build(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /example/android/dna-compiler/src/main/java/me/ele/dna_compiler/DnaPackageFinder.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_compiler; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DnaPackageFinder { 7 | 8 | private List infoList; 9 | 10 | public DnaPackageFinder() { 11 | infoList = new ArrayList<>(); 12 | } 13 | 14 | public void addMethodInfo(String packgeName, BaseDnaElement methodInfo) { 15 | DnaClassFinder temProxy; 16 | if (infoList == null) { 17 | infoList = new ArrayList<>(); 18 | } 19 | if (!infoList.isEmpty()) { 20 | for (DnaClassFinder packageProxy : infoList) { 21 | if (packageProxy.getPackageName() != null && packageProxy.getPackageName().equals(packgeName)) { 22 | packageProxy.addMethodInfo(methodInfo); 23 | return; 24 | } 25 | } 26 | } 27 | temProxy = new DnaClassFinder(packgeName); 28 | temProxy.addMethodInfo(methodInfo); 29 | infoList.add(temProxy); 30 | return; 31 | } 32 | 33 | 34 | public List getInfoList() { 35 | return infoList; 36 | } 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /example/android/dna-compiler/src/main/java/me/ele/dna_compiler/DnaProcessor.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_compiler; 2 | 3 | import com.squareup.javapoet.TypeName; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedHashSet; 7 | import java.util.List; 8 | import java.util.Set; 9 | 10 | import javax.annotation.processing.AbstractProcessor; 11 | import javax.annotation.processing.Filer; 12 | import javax.annotation.processing.Messager; 13 | import javax.annotation.processing.ProcessingEnvironment; 14 | import javax.annotation.processing.RoundEnvironment; 15 | import javax.lang.model.SourceVersion; 16 | import javax.lang.model.element.Element; 17 | import javax.lang.model.element.ExecutableElement; 18 | import javax.lang.model.element.Modifier; 19 | import javax.lang.model.element.TypeElement; 20 | import javax.lang.model.element.VariableElement; 21 | import javax.lang.model.type.TypeKind; 22 | import javax.lang.model.type.TypeMirror; 23 | import javax.lang.model.type.TypeVariable; 24 | import javax.lang.model.util.Elements; 25 | import javax.lang.model.util.Types; 26 | 27 | import me.ele.dna_annotations.DnaConstants; 28 | import me.ele.dna_annotations.DnaMethod; 29 | 30 | import static javax.lang.model.element.ElementKind.CLASS; 31 | import static javax.lang.model.element.ElementKind.CONSTRUCTOR; 32 | import static javax.lang.model.element.ElementKind.METHOD; 33 | import static javax.lang.model.element.Modifier.PRIVATE; 34 | 35 | public class DnaProcessor extends AbstractProcessor { 36 | 37 | private Messager messager; 38 | private Elements elementUtils; 39 | private Filer filer; 40 | private Types typeUtils; 41 | 42 | /** 43 | * ` 44 | * 初始化操作 45 | * 46 | * @param processingEnvironment 47 | */ 48 | @Override 49 | public synchronized void init(ProcessingEnvironment processingEnvironment) { 50 | super.init(processingEnvironment); 51 | typeUtils = processingEnvironment.getTypeUtils(); 52 | elementUtils = processingEnvironment.getElementUtils(); 53 | filer = processingEnvironment.getFiler(); 54 | messager = processingEnvironment.getMessager(); 55 | } 56 | 57 | @Override 58 | public Set getSupportedOptions() { 59 | return super.getSupportedOptions(); 60 | } 61 | 62 | @Override 63 | public SourceVersion getSupportedSourceVersion() { 64 | return SourceVersion.latestSupported(); 65 | } 66 | 67 | @Override 68 | public Set getSupportedAnnotationTypes() { 69 | Set set = new LinkedHashSet<>(); 70 | set.add(DnaMethod.class.getCanonicalName()); 71 | return set; 72 | } 73 | 74 | 75 | @Override 76 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 77 | List classFinders = getMethodInfos(roundEnv); 78 | if (classFinders != null && !classFinders.isEmpty()) { 79 | for (DnaClassFinder finder : classFinders) { 80 | try { 81 | finder.createJavaFile().writeTo(filer); 82 | } catch (Exception e) { 83 | e.printStackTrace(); 84 | } 85 | } 86 | } 87 | return false; 88 | } 89 | 90 | private List getMethodInfos(RoundEnvironment roundEnv) { 91 | DnaPackageFinder finder = new DnaPackageFinder(); 92 | String packageName; 93 | Set annotatedElements = roundEnv.getElementsAnnotatedWith(DnaMethod.class); 94 | BaseDnaElement dnaElement; 95 | for (Element element : annotatedElements) { 96 | if (!(element instanceof ExecutableElement) || (element.getKind() != METHOD && element.getKind() != CONSTRUCTOR)) { 97 | throw new IllegalStateException("DnaMethod annotation must be on a method."); 98 | } 99 | boolean isReturn; 100 | ExecutableElement executableElement = (ExecutableElement) element; 101 | TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); 102 | String methodName; 103 | if (!isAccessible(element)) { 104 | throw new IllegalStateException(" annotated method can't access."); 105 | } 106 | List parameters = executableElement.getParameters(); 107 | TypeMirror methodParameterType; 108 | packageName = elementUtils.getPackageOf(element).getQualifiedName().toString(); 109 | List paramterType = new ArrayList<>(); 110 | if (parameters != null && parameters.size() != 0) { 111 | for (VariableElement variableElement : parameters) { 112 | methodParameterType = variableElement.asType(); 113 | if (methodParameterType instanceof TypeVariable) { 114 | TypeVariable typeVariable = (TypeVariable) methodParameterType; 115 | methodParameterType = typeVariable.getUpperBound(); 116 | } 117 | paramterType.add(new ParamInfo(methodParameterType.toString(), TypeName.get(methodParameterType))); 118 | 119 | } 120 | } 121 | TypeMirror returnType = executableElement.getReturnType(); 122 | String reutrnName = returnType.toString(); 123 | if (element.getKind() == CONSTRUCTOR) { 124 | methodName = enclosingElement.getSimpleName().toString(); 125 | dnaElement = new DnaConstructorInfo(paramterType, enclosingElement, DnaConstants.PROXYCONSTRUCTOR.concat(methodName), reutrnName); 126 | } else { 127 | methodName = executableElement.getSimpleName().toString(); 128 | isReturn = returnType != null && returnType.getKind() != TypeKind.VOID; 129 | dnaElement = new DnaMethodInfo(paramterType, enclosingElement, methodName, isReturn, reutrnName); 130 | } 131 | 132 | finder.addMethodInfo(packageName, dnaElement); 133 | } 134 | return finder.getInfoList(); 135 | 136 | } 137 | 138 | private boolean isAccessible(Element element) { 139 | Set modifiers = element.getModifiers(); 140 | TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); 141 | 142 | if (modifiers.contains(PRIVATE)) { 143 | return false; 144 | } 145 | 146 | if (enclosingElement.getKind() != CLASS || enclosingElement.getModifiers().contains(PRIVATE)) { 147 | return false; 148 | } 149 | 150 | return true; 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /example/android/dna-compiler/src/main/java/me/ele/dna_compiler/ParamInfo.java: -------------------------------------------------------------------------------- 1 | package me.ele.dna_compiler; 2 | 3 | import com.squareup.javapoet.TypeName; 4 | 5 | public class ParamInfo { 6 | String className; 7 | TypeName typeName; 8 | 9 | public ParamInfo(String className, TypeName typeName) { 10 | this.className = className; 11 | this.typeName = typeName; 12 | } 13 | 14 | public String getClassName() { 15 | return className; 16 | } 17 | 18 | public TypeName getTypeName() { 19 | return typeName; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /example/android/dna-compiler/src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | me.ele.dna_compiler.DnaProcessor -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/example/android/gradle.properties -------------------------------------------------------------------------------- /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.10.2-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':dna-compiler', ':dna-annotations' 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/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/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 | - dna (0.0.1): 3 | - Flutter 4 | - YYModel 5 | - Flutter (1.0.0) 6 | - YYModel (1.0.4) 7 | 8 | DEPENDENCIES: 9 | - dna (from `.symlinks/plugins/dna/ios`) 10 | - Flutter (from `.symlinks/flutter/ios`) 11 | 12 | SPEC REPOS: 13 | https://github.com/cocoapods/specs.git: 14 | - YYModel 15 | 16 | EXTERNAL SOURCES: 17 | dna: 18 | :path: ".symlinks/plugins/dna/ios" 19 | Flutter: 20 | :path: ".symlinks/flutter/ios" 21 | 22 | SPEC CHECKSUMS: 23 | dna: de6646a5384fbc67918f4d1660673bdba824dae7 24 | Flutter: 9d0fac939486c9aba2809b7982dfdbb47a7b0296 25 | YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30 26 | 27 | PODFILE CHECKSUM: 3389836f37640698630b8f0670315d626d5f1469 28 | 29 | COCOAPODS: 1.5.3 30 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 15 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 17 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 18 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 19 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 20 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 21 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 22 | E3CFC2FBA3EFAA3A631F71C1 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A65BEB49930F6DF43C86C42 /* libPods-Runner.a */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXCopyFilesBuildPhase section */ 26 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 27 | isa = PBXCopyFilesBuildPhase; 28 | buildActionMask = 2147483647; 29 | dstPath = ""; 30 | dstSubfolderSpec = 10; 31 | files = ( 32 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 33 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 34 | ); 35 | name = "Embed Frameworks"; 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXCopyFilesBuildPhase section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 0A65BEB49930F6DF43C86C42 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 43 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 50 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 51 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 52 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 66 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 67 | E3CFC2FBA3EFAA3A631F71C1 /* libPods-Runner.a in Frameworks */, 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | /* End PBXFrameworksBuildPhase section */ 72 | 73 | /* Begin PBXGroup section */ 74 | 9740EEB11CF90186004384FC /* Flutter */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 3B80C3931E831B6300D905FE /* App.framework */, 78 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 79 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 80 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 81 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 82 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 83 | ); 84 | name = Flutter; 85 | sourceTree = ""; 86 | }; 87 | 97C146E51CF9000F007C117D = { 88 | isa = PBXGroup; 89 | children = ( 90 | 9740EEB11CF90186004384FC /* Flutter */, 91 | 97C146F01CF9000F007C117D /* Runner */, 92 | 97C146EF1CF9000F007C117D /* Products */, 93 | A6616C248645BB21C226DCDD /* Pods */, 94 | F6D482DBDF21B5F3B566A03E /* Frameworks */, 95 | ); 96 | sourceTree = ""; 97 | }; 98 | 97C146EF1CF9000F007C117D /* Products */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 97C146EE1CF9000F007C117D /* Runner.app */, 102 | ); 103 | name = Products; 104 | sourceTree = ""; 105 | }; 106 | 97C146F01CF9000F007C117D /* Runner */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 110 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 111 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 112 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 113 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 114 | 97C147021CF9000F007C117D /* Info.plist */, 115 | 97C146F11CF9000F007C117D /* Supporting Files */, 116 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 117 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 118 | ); 119 | path = Runner; 120 | sourceTree = ""; 121 | }; 122 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 97C146F21CF9000F007C117D /* main.m */, 126 | ); 127 | name = "Supporting Files"; 128 | sourceTree = ""; 129 | }; 130 | A6616C248645BB21C226DCDD /* Pods */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | ); 134 | name = Pods; 135 | sourceTree = ""; 136 | }; 137 | F6D482DBDF21B5F3B566A03E /* Frameworks */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 0A65BEB49930F6DF43C86C42 /* libPods-Runner.a */, 141 | ); 142 | name = Frameworks; 143 | sourceTree = ""; 144 | }; 145 | /* End PBXGroup section */ 146 | 147 | /* Begin PBXNativeTarget section */ 148 | 97C146ED1CF9000F007C117D /* Runner */ = { 149 | isa = PBXNativeTarget; 150 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 151 | buildPhases = ( 152 | F38B7F5F662F7823958ED7F4 /* [CP] Check Pods Manifest.lock */, 153 | 9740EEB61CF901F6004384FC /* Run Script */, 154 | 97C146EA1CF9000F007C117D /* Sources */, 155 | 97C146EB1CF9000F007C117D /* Frameworks */, 156 | 97C146EC1CF9000F007C117D /* Resources */, 157 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 158 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 159 | 3B6AFBCB775D17CA43AF09CB /* [CP] Embed Pods Frameworks */, 160 | ); 161 | buildRules = ( 162 | ); 163 | dependencies = ( 164 | ); 165 | name = Runner; 166 | productName = Runner; 167 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 168 | productType = "com.apple.product-type.application"; 169 | }; 170 | /* End PBXNativeTarget section */ 171 | 172 | /* Begin PBXProject section */ 173 | 97C146E61CF9000F007C117D /* Project object */ = { 174 | isa = PBXProject; 175 | attributes = { 176 | LastUpgradeCheck = 0910; 177 | ORGANIZATIONNAME = "The Chromium Authors"; 178 | TargetAttributes = { 179 | 97C146ED1CF9000F007C117D = { 180 | CreatedOnToolsVersion = 7.3.1; 181 | }; 182 | }; 183 | }; 184 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 185 | compatibilityVersion = "Xcode 3.2"; 186 | developmentRegion = English; 187 | hasScannedForEncodings = 0; 188 | knownRegions = ( 189 | English, 190 | en, 191 | Base, 192 | ); 193 | mainGroup = 97C146E51CF9000F007C117D; 194 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 195 | projectDirPath = ""; 196 | projectRoot = ""; 197 | targets = ( 198 | 97C146ED1CF9000F007C117D /* Runner */, 199 | ); 200 | }; 201 | /* End PBXProject section */ 202 | 203 | /* Begin PBXResourcesBuildPhase section */ 204 | 97C146EC1CF9000F007C117D /* Resources */ = { 205 | isa = PBXResourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 209 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 210 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 211 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 212 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | }; 216 | /* End PBXResourcesBuildPhase section */ 217 | 218 | /* Begin PBXShellScriptBuildPhase section */ 219 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 220 | isa = PBXShellScriptBuildPhase; 221 | buildActionMask = 2147483647; 222 | files = ( 223 | ); 224 | inputPaths = ( 225 | ); 226 | name = "Thin Binary"; 227 | outputPaths = ( 228 | ); 229 | runOnlyForDeploymentPostprocessing = 0; 230 | shellPath = /bin/sh; 231 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 232 | }; 233 | 3B6AFBCB775D17CA43AF09CB /* [CP] Embed Pods Frameworks */ = { 234 | isa = PBXShellScriptBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | ); 238 | inputFileListPaths = ( 239 | ); 240 | inputPaths = ( 241 | "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", 242 | "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", 243 | ); 244 | name = "[CP] Embed Pods Frameworks"; 245 | outputFileListPaths = ( 246 | ); 247 | outputPaths = ( 248 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | shellPath = /bin/sh; 252 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 253 | showEnvVarsInLog = 0; 254 | }; 255 | 9740EEB61CF901F6004384FC /* Run Script */ = { 256 | isa = PBXShellScriptBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | ); 260 | inputPaths = ( 261 | ); 262 | name = "Run Script"; 263 | outputPaths = ( 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | shellPath = /bin/sh; 267 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 268 | }; 269 | F38B7F5F662F7823958ED7F4 /* [CP] Check Pods Manifest.lock */ = { 270 | isa = PBXShellScriptBuildPhase; 271 | buildActionMask = 2147483647; 272 | files = ( 273 | ); 274 | inputFileListPaths = ( 275 | ); 276 | inputPaths = ( 277 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 278 | "${PODS_ROOT}/Manifest.lock", 279 | ); 280 | name = "[CP] Check Pods Manifest.lock"; 281 | outputFileListPaths = ( 282 | ); 283 | outputPaths = ( 284 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 285 | ); 286 | runOnlyForDeploymentPostprocessing = 0; 287 | shellPath = /bin/sh; 288 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 289 | showEnvVarsInLog = 0; 290 | }; 291 | /* End PBXShellScriptBuildPhase section */ 292 | 293 | /* Begin PBXSourcesBuildPhase section */ 294 | 97C146EA1CF9000F007C117D /* Sources */ = { 295 | isa = PBXSourcesBuildPhase; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 299 | 97C146F31CF9000F007C117D /* main.m in Sources */, 300 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | /* End PBXSourcesBuildPhase section */ 305 | 306 | /* Begin PBXVariantGroup section */ 307 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 308 | isa = PBXVariantGroup; 309 | children = ( 310 | 97C146FB1CF9000F007C117D /* Base */, 311 | ); 312 | name = Main.storyboard; 313 | sourceTree = ""; 314 | }; 315 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 316 | isa = PBXVariantGroup; 317 | children = ( 318 | 97C147001CF9000F007C117D /* Base */, 319 | ); 320 | name = LaunchScreen.storyboard; 321 | sourceTree = ""; 322 | }; 323 | /* End PBXVariantGroup section */ 324 | 325 | /* Begin XCBuildConfiguration section */ 326 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 327 | isa = XCBuildConfiguration; 328 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 329 | buildSettings = { 330 | ALWAYS_SEARCH_USER_PATHS = NO; 331 | CLANG_ANALYZER_NONNULL = YES; 332 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 333 | CLANG_CXX_LIBRARY = "libc++"; 334 | CLANG_ENABLE_MODULES = YES; 335 | CLANG_ENABLE_OBJC_ARC = YES; 336 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 337 | CLANG_WARN_BOOL_CONVERSION = YES; 338 | CLANG_WARN_COMMA = YES; 339 | CLANG_WARN_CONSTANT_CONVERSION = YES; 340 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 341 | CLANG_WARN_EMPTY_BODY = YES; 342 | CLANG_WARN_ENUM_CONVERSION = YES; 343 | CLANG_WARN_INFINITE_RECURSION = YES; 344 | CLANG_WARN_INT_CONVERSION = YES; 345 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 346 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 347 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 348 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 349 | CLANG_WARN_STRICT_PROTOTYPES = YES; 350 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 351 | CLANG_WARN_UNREACHABLE_CODE = YES; 352 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 353 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 354 | COPY_PHASE_STRIP = NO; 355 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 356 | ENABLE_NS_ASSERTIONS = NO; 357 | ENABLE_STRICT_OBJC_MSGSEND = YES; 358 | GCC_C_LANGUAGE_STANDARD = gnu99; 359 | GCC_NO_COMMON_BLOCKS = YES; 360 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 361 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 362 | GCC_WARN_UNDECLARED_SELECTOR = YES; 363 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 364 | GCC_WARN_UNUSED_FUNCTION = YES; 365 | GCC_WARN_UNUSED_VARIABLE = YES; 366 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 367 | MTL_ENABLE_DEBUG_INFO = NO; 368 | SDKROOT = iphoneos; 369 | TARGETED_DEVICE_FAMILY = "1,2"; 370 | VALIDATE_PRODUCT = YES; 371 | }; 372 | name = Profile; 373 | }; 374 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 375 | isa = XCBuildConfiguration; 376 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 377 | buildSettings = { 378 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 379 | CURRENT_PROJECT_VERSION = 100; 380 | DEVELOPMENT_TEAM = S8QB4VV633; 381 | ENABLE_BITCODE = NO; 382 | FRAMEWORK_SEARCH_PATHS = ( 383 | "$(inherited)", 384 | "$(PROJECT_DIR)/Flutter", 385 | ); 386 | INFOPLIST_FILE = Runner/Info.plist; 387 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 388 | LIBRARY_SEARCH_PATHS = ( 389 | "$(inherited)", 390 | "$(PROJECT_DIR)/Flutter", 391 | ); 392 | MARKETING_VERSION = 1.0.0; 393 | PRODUCT_BUNDLE_IDENTIFIER = com.example.dnaExample; 394 | PRODUCT_NAME = "$(TARGET_NAME)"; 395 | VERSIONING_SYSTEM = "apple-generic"; 396 | }; 397 | name = Profile; 398 | }; 399 | 97C147031CF9000F007C117D /* Debug */ = { 400 | isa = XCBuildConfiguration; 401 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 402 | buildSettings = { 403 | ALWAYS_SEARCH_USER_PATHS = NO; 404 | CLANG_ANALYZER_NONNULL = YES; 405 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 406 | CLANG_CXX_LIBRARY = "libc++"; 407 | CLANG_ENABLE_MODULES = YES; 408 | CLANG_ENABLE_OBJC_ARC = YES; 409 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 410 | CLANG_WARN_BOOL_CONVERSION = YES; 411 | CLANG_WARN_COMMA = YES; 412 | CLANG_WARN_CONSTANT_CONVERSION = YES; 413 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 414 | CLANG_WARN_EMPTY_BODY = YES; 415 | CLANG_WARN_ENUM_CONVERSION = YES; 416 | CLANG_WARN_INFINITE_RECURSION = YES; 417 | CLANG_WARN_INT_CONVERSION = YES; 418 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 419 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 420 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 421 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 422 | CLANG_WARN_STRICT_PROTOTYPES = YES; 423 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 424 | CLANG_WARN_UNREACHABLE_CODE = YES; 425 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 426 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 427 | COPY_PHASE_STRIP = NO; 428 | DEBUG_INFORMATION_FORMAT = dwarf; 429 | ENABLE_STRICT_OBJC_MSGSEND = YES; 430 | ENABLE_TESTABILITY = YES; 431 | GCC_C_LANGUAGE_STANDARD = gnu99; 432 | GCC_DYNAMIC_NO_PIC = NO; 433 | GCC_NO_COMMON_BLOCKS = YES; 434 | GCC_OPTIMIZATION_LEVEL = 0; 435 | GCC_PREPROCESSOR_DEFINITIONS = ( 436 | "DEBUG=1", 437 | "$(inherited)", 438 | ); 439 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 440 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 441 | GCC_WARN_UNDECLARED_SELECTOR = YES; 442 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 443 | GCC_WARN_UNUSED_FUNCTION = YES; 444 | GCC_WARN_UNUSED_VARIABLE = YES; 445 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 446 | MTL_ENABLE_DEBUG_INFO = YES; 447 | ONLY_ACTIVE_ARCH = YES; 448 | SDKROOT = iphoneos; 449 | TARGETED_DEVICE_FAMILY = "1,2"; 450 | }; 451 | name = Debug; 452 | }; 453 | 97C147041CF9000F007C117D /* Release */ = { 454 | isa = XCBuildConfiguration; 455 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 456 | buildSettings = { 457 | ALWAYS_SEARCH_USER_PATHS = NO; 458 | CLANG_ANALYZER_NONNULL = YES; 459 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 460 | CLANG_CXX_LIBRARY = "libc++"; 461 | CLANG_ENABLE_MODULES = YES; 462 | CLANG_ENABLE_OBJC_ARC = YES; 463 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 464 | CLANG_WARN_BOOL_CONVERSION = YES; 465 | CLANG_WARN_COMMA = YES; 466 | CLANG_WARN_CONSTANT_CONVERSION = YES; 467 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 468 | CLANG_WARN_EMPTY_BODY = YES; 469 | CLANG_WARN_ENUM_CONVERSION = YES; 470 | CLANG_WARN_INFINITE_RECURSION = YES; 471 | CLANG_WARN_INT_CONVERSION = YES; 472 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 473 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 474 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 475 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 476 | CLANG_WARN_STRICT_PROTOTYPES = YES; 477 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 478 | CLANG_WARN_UNREACHABLE_CODE = YES; 479 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 480 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 481 | COPY_PHASE_STRIP = NO; 482 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 483 | ENABLE_NS_ASSERTIONS = NO; 484 | ENABLE_STRICT_OBJC_MSGSEND = YES; 485 | GCC_C_LANGUAGE_STANDARD = gnu99; 486 | GCC_NO_COMMON_BLOCKS = YES; 487 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 488 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 489 | GCC_WARN_UNDECLARED_SELECTOR = YES; 490 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 491 | GCC_WARN_UNUSED_FUNCTION = YES; 492 | GCC_WARN_UNUSED_VARIABLE = YES; 493 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 494 | MTL_ENABLE_DEBUG_INFO = NO; 495 | SDKROOT = iphoneos; 496 | TARGETED_DEVICE_FAMILY = "1,2"; 497 | VALIDATE_PRODUCT = YES; 498 | }; 499 | name = Release; 500 | }; 501 | 97C147061CF9000F007C117D /* Debug */ = { 502 | isa = XCBuildConfiguration; 503 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 504 | buildSettings = { 505 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 506 | CURRENT_PROJECT_VERSION = 100; 507 | ENABLE_BITCODE = NO; 508 | FRAMEWORK_SEARCH_PATHS = ( 509 | "$(inherited)", 510 | "$(PROJECT_DIR)/Flutter", 511 | ); 512 | INFOPLIST_FILE = Runner/Info.plist; 513 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 514 | LIBRARY_SEARCH_PATHS = ( 515 | "$(inherited)", 516 | "$(PROJECT_DIR)/Flutter", 517 | ); 518 | MARKETING_VERSION = 1.0.0; 519 | PRODUCT_BUNDLE_IDENTIFIER = com.example.dnaExample; 520 | PRODUCT_NAME = "$(TARGET_NAME)"; 521 | VERSIONING_SYSTEM = "apple-generic"; 522 | }; 523 | name = Debug; 524 | }; 525 | 97C147071CF9000F007C117D /* Release */ = { 526 | isa = XCBuildConfiguration; 527 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 528 | buildSettings = { 529 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 530 | CURRENT_PROJECT_VERSION = 100; 531 | ENABLE_BITCODE = NO; 532 | FRAMEWORK_SEARCH_PATHS = ( 533 | "$(inherited)", 534 | "$(PROJECT_DIR)/Flutter", 535 | ); 536 | INFOPLIST_FILE = Runner/Info.plist; 537 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 538 | LIBRARY_SEARCH_PATHS = ( 539 | "$(inherited)", 540 | "$(PROJECT_DIR)/Flutter", 541 | ); 542 | MARKETING_VERSION = 1.0.0; 543 | PRODUCT_BUNDLE_IDENTIFIER = com.example.dnaExample; 544 | PRODUCT_NAME = "$(TARGET_NAME)"; 545 | VERSIONING_SYSTEM = "apple-generic"; 546 | }; 547 | name = Release; 548 | }; 549 | /* End XCBuildConfiguration section */ 550 | 551 | /* Begin XCConfigurationList section */ 552 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 553 | isa = XCConfigurationList; 554 | buildConfigurations = ( 555 | 97C147031CF9000F007C117D /* Debug */, 556 | 97C147041CF9000F007C117D /* Release */, 557 | 249021D3217E4FDB00AE95B9 /* Profile */, 558 | ); 559 | defaultConfigurationIsVisible = 0; 560 | defaultConfigurationName = Release; 561 | }; 562 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 563 | isa = XCConfigurationList; 564 | buildConfigurations = ( 565 | 97C147061CF9000F007C117D /* Debug */, 566 | 97C147071CF9000F007C117D /* Release */, 567 | 249021D4217E4FDB00AE95B9 /* Profile */, 568 | ); 569 | defaultConfigurationIsVisible = 0; 570 | defaultConfigurationName = Release; 571 | }; 572 | /* End XCConfigurationList section */ 573 | }; 574 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 575 | } 576 | -------------------------------------------------------------------------------- /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 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /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 | // Override point for customization after application launch. 10 | 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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/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 | 28 | 29 | -------------------------------------------------------------------------------- /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 | dna_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 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 | import 'package:flutter/services.dart'; 4 | import 'package:dna/dna.dart'; 5 | 6 | void main() => runApp(MyApp()); 7 | 8 | class MyApp extends StatefulWidget { 9 | @override 10 | _MyAppState createState() => _MyAppState(); 11 | } 12 | 13 | class _MyAppState extends State { 14 | String _platformVersion = 'Unknown'; 15 | @override 16 | void initState() { 17 | super.initState(); 18 | initPlatformState(); 19 | } 20 | 21 | // Platform messages are asynchronous, so we initialize in an async method. 22 | Future initPlatformState() async { 23 | String platformVersion; 24 | // Platform messages may fail, so we use a try/catch PlatformException. 25 | 26 | try { 27 | platformVersion = await Dna.traversingNative((ObjCContext context) { 28 | NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion'); 29 | version = context.classFromString("NSString").invoke(method: 'stringWithString:', args: ['iOS-']).invoke(method: 'stringByAppendingString:', args: [version]); 30 | context.returnVar = version; // 该句可省略 31 | }, (JAVAContext context) { 32 | NativeObject versionId = context.newJavaObjectFromConstructor('me.ele.dna_example.DnaTest', null).invoke(method: 'getDnaVersion').invoke(method: 'getVersion'); 33 | NativeObject version = context.newJavaObjectFromConstructor('java.lang.String', ["android "]).invoke(method: "concat", args: [versionId]); 34 | context.returnVar = version; // 该句可省略 35 | }); 36 | 37 | // ObjCContext context = ObjCContext(); 38 | // NativeObject version = context.classFromString('UIDevice').invoke(method: 'currentDevice').invoke(method: 'systemVersion'); 39 | // context.classFromString('NSString').invoke(method: 'stringWithString:', args: ['IOS-']).invoke(method:'stringByAppendingString:',args: [version]); 40 | 41 | // NativeObject objectA = context.newNativeObjectFromJSON({'a':1, 'b':2}, 'ClassA'); 42 | // NativeObject objectB = context.classFromString('ClassB').invoke(method: 'new'); 43 | // objectB.invoke(method: 'setC:',args: [3]); 44 | // objectB.invoke(method: 'sum:',args: [objectA]); 45 | 46 | // int x = await context.execute(); 47 | // platformVersion = await context.execute(); 48 | 49 | // android 测试代码 50 | /* NativeObject objectA = context 51 | .classFromString("com.example.dna_example.DnaTest") 52 | .invoke(method: "getDna") 53 | .invoke(method: "HelloDna", args: ["Hello dna"]); 54 | NativeObject objectC = context.newNativeObjectFromJSON( 55 | {'a': 1, 'b': 2}, 'com.example.dna_example.TestModel'); 56 | NativeObject objectB = context 57 | .classFromString('com.example.dna_example.DnaComTest') 58 | .invoke(method: 'printlin', args: [objectA]).invoke( 59 | method: 'printlin', args: [objectC]);*/ 60 | 61 | } on PlatformException { 62 | platformVersion = 'Failed to get platform version.'; 63 | } 64 | 65 | // If the widget was removed from the tree while the asynchronous platform 66 | // message was in flight, we want to discard the reply rather than calling 67 | // setState to update our non-existent appearance. 68 | if (!mounted) return; 69 | 70 | setState(() { 71 | _platformVersion = platformVersion; 72 | }); 73 | } 74 | 75 | @override 76 | Widget build(BuildContext context) { 77 | initPlatformState(); 78 | return MaterialApp( 79 | home: Scaffold( 80 | appBar: AppBar( 81 | title: const Text('Plugin example app'), 82 | ), 83 | body: Center( 84 | child: Text('Running on: $_platformVersion\n'), 85 | ), 86 | ), 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.1.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.4" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.2" 25 | collection: 26 | dependency: transitive 27 | description: 28 | name: collection 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.14.11" 32 | cupertino_icons: 33 | dependency: "direct main" 34 | description: 35 | name: cupertino_icons 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "0.1.3" 39 | dna: 40 | dependency: "direct dev" 41 | description: 42 | path: ".." 43 | relative: true 44 | source: path 45 | version: "0.0.1" 46 | flutter: 47 | dependency: "direct main" 48 | description: flutter 49 | source: sdk 50 | version: "0.0.0" 51 | flutter_test: 52 | dependency: "direct dev" 53 | description: flutter 54 | source: sdk 55 | version: "0.0.0" 56 | matcher: 57 | dependency: transitive 58 | description: 59 | name: matcher 60 | url: "https://pub.dartlang.org" 61 | source: hosted 62 | version: "0.12.5" 63 | meta: 64 | dependency: transitive 65 | description: 66 | name: meta 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "1.1.6" 70 | path: 71 | dependency: transitive 72 | description: 73 | name: path 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "1.6.2" 77 | pedantic: 78 | dependency: transitive 79 | description: 80 | name: pedantic 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "1.5.0" 84 | quiver: 85 | dependency: transitive 86 | description: 87 | name: quiver 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "2.0.2" 91 | sky_engine: 92 | dependency: transitive 93 | description: flutter 94 | source: sdk 95 | version: "0.0.99" 96 | source_span: 97 | dependency: transitive 98 | description: 99 | name: source_span 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "1.5.5" 103 | stack_trace: 104 | dependency: transitive 105 | description: 106 | name: stack_trace 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.9.3" 110 | stream_channel: 111 | dependency: transitive 112 | description: 113 | name: stream_channel 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "2.0.0" 117 | string_scanner: 118 | dependency: transitive 119 | description: 120 | name: string_scanner 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.0.4" 124 | term_glyph: 125 | dependency: transitive 126 | description: 127 | name: term_glyph 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.1.0" 131 | test_api: 132 | dependency: transitive 133 | description: 134 | name: test_api 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "0.2.4" 138 | typed_data: 139 | dependency: transitive 140 | description: 141 | name: typed_data 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.1.6" 145 | vector_math: 146 | dependency: transitive 147 | description: 148 | name: vector_math 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "2.0.8" 152 | sdks: 153 | dart: ">=2.2.0 <3.0.0" 154 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dna_example 2 | description: Demonstrates how to use the dna plugin. 3 | publish_to: 'none' 4 | 5 | environment: 6 | sdk: ">=2.1.0 <3.0.0" 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | 12 | # The following adds the Cupertino Icons font to your application. 13 | # Use with the CupertinoIcons class for iOS style icons. 14 | cupertino_icons: ^0.1.2 15 | 16 | dev_dependencies: 17 | flutter_test: 18 | sdk: flutter 19 | 20 | dna: 21 | path: ../ 22 | 23 | # For information on the generic Dart part of this file, see the 24 | # following page: https://www.dartlang.org/tools/pub/pubspec 25 | 26 | # The following section is specific to Flutter. 27 | flutter: 28 | 29 | # The following line ensures that the Material Icons font is 30 | # included with your application, so that you can use the icons in 31 | # the material Icons class. 32 | uses-material-design: true 33 | 34 | # To add assets to your application, add an assets section, like this: 35 | # assets: 36 | # - images/a_dot_burr.jpeg 37 | # - images/a_dot_ham.jpeg 38 | 39 | # An image asset can refer to one or more resolution-specific "variants", see 40 | # https://flutter.dev/assets-and-images/#resolution-aware. 41 | 42 | # For details regarding adding assets from package dependencies, see 43 | # https://flutter.dev/assets-and-images/#from-packages 44 | 45 | # To add custom fonts to your application, add a fonts section here, 46 | # in this "flutter" section. Each entry in this list should have a 47 | # "family" key with the font family name, and a "fonts" key with a 48 | # list giving the asset and other descriptors for the font. For 49 | # example: 50 | # fonts: 51 | # - family: Schyler 52 | # fonts: 53 | # - asset: fonts/Schyler-Regular.ttf 54 | # - asset: fonts/Schyler-Italic.ttf 55 | # style: italic 56 | # - family: Trajan Pro 57 | # fonts: 58 | # - asset: fonts/TrajanPro.ttf 59 | # - asset: fonts/TrajanPro_Bold.ttf 60 | # weight: 700 61 | # 62 | # For details regarding fonts from package dependencies, 63 | # see https://flutter.dev/custom-fonts/#from-packages 64 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:dna_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => widget is Text && 22 | widget.data.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /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/eleme/dna/914322e3b5c90bb7da9838f9d43859c8aaf79f9f/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/DnaPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface DnaPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /ios/Classes/DnaPlugin.m: -------------------------------------------------------------------------------- 1 | #import "DnaPlugin.h" 2 | #import 3 | #import 4 | 5 | //@interface ClassA : NSObject 6 | //@property (nonatomic) NSInteger a; 7 | //@property (nonatomic) NSInteger b; 8 | //@end 9 | //@implementation ClassA 10 | //@end 11 | // 12 | //@interface ClassB : NSObject 13 | //@property (nonatomic) NSInteger c; 14 | //@end 15 | //@implementation ClassB 16 | // 17 | //- (NSInteger)sum:(ClassA *)objectA { 18 | // return self.c + objectA.a + objectA.b; 19 | //} 20 | //@end 21 | 22 | @implementation DnaPlugin 23 | + (void)registerWithRegistrar:(NSObject*)registrar { 24 | FlutterMethodChannel* channel = [FlutterMethodChannel 25 | methodChannelWithName:@"dna" 26 | binaryMessenger:[registrar messenger]]; 27 | DnaPlugin* instance = [[DnaPlugin alloc] init]; 28 | [registrar addMethodCallDelegate:instance channel:channel]; 29 | } 30 | 31 | - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { 32 | if ([@"getPlatformVersion" isEqualToString:call.method]) { 33 | result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]); 34 | } else if ([@"executeNativeContext" isEqualToString:call.method]) { 35 | [self executeNativeContext:call.arguments result:result]; 36 | } else { 37 | result(FlutterMethodNotImplemented); 38 | } 39 | } 40 | 41 | 42 | 43 | NSString * const dna_objectId = @"_objectId"; 44 | NSString * const dna_clsName = @"clsName"; 45 | 46 | NSString * const dna_objectJSONWrappers = @"_objectJSONWrappers"; 47 | NSString * const dna_json = @"json"; 48 | NSString * const dna_cls = @"cls"; 49 | 50 | NSString * const dna_invocationNodes = @"_invocationNodes"; 51 | NSString * const dna_object = @"object"; 52 | NSString * const dna_method = @"method"; 53 | NSString * const dna_args = @"args"; 54 | 55 | NSString * const dna_returnVar = @"returnVar"; 56 | 57 | - (void)executeNativeContext:(NSDictionary *)context result:(FlutterResult)result { 58 | // key : _objectId, value: object 59 | NSMutableDictionary *objectsInContextMap = [NSMutableDictionary dictionary]; 60 | 61 | // 直接根据objectJSONWrapper生成对象,以_objectId为键,加入到objectsInContextMap中 62 | NSArray *_objectJSONWrappers = context[dna_objectJSONWrappers]; 63 | for (NSDictionary *objectJSONWrapper in _objectJSONWrappers) { 64 | NSDictionary *json = objectJSONWrapper[dna_json]; 65 | NSString *cls = objectJSONWrapper[dna_cls]; 66 | id object = [NSClassFromString(cls) yy_modelWithJSON:json]; 67 | if (object) { 68 | NSString *objectId = dna_getObjectId(objectJSONWrapper); 69 | objectsInContextMap[objectId] = object; 70 | } 71 | } 72 | 73 | // 得到context returnVar对应的_objectId 74 | NSDictionary *contextReturnVar = context[dna_returnVar]; 75 | BOOL hasContextReturnVarFlag = dna_isAvailable(contextReturnVar); 76 | NSString *contextReturnVarObjectId = nil; 77 | if (hasContextReturnVarFlag) { 78 | contextReturnVarObjectId = dna_getObjectId(contextReturnVar); 79 | } 80 | 81 | // 陆续调用所有Invocation 82 | NSArray *_invocationNodes = context[dna_invocationNodes]; 83 | for (NSUInteger i = 0; i < _invocationNodes.count; i++) { 84 | NSDictionary *invocation = _invocationNodes[i]; 85 | 86 | // 得到当前调用方法的对象,类或实例; 87 | NSObject *object = nil; 88 | NSDictionary *objectInfo = invocation[dna_object]; 89 | if (dna_isAvailable(dna_getObjectId(objectInfo))) { 90 | // 根据_objectId得到,可能是其他invocation的返回值 / 从objectJSONWrapper生成 91 | object = objectsInContextMap[dna_getObjectId(objectInfo)]; 92 | if (!object && dna_isAvailable(objectInfo[dna_clsName])) { 93 | // 根据类名获取到类对象,并加入到变量表里 94 | object = (id)NSClassFromString(objectInfo[dna_clsName]); 95 | if (object) { 96 | objectsInContextMap[dna_getObjectId(objectInfo)] = object; 97 | } 98 | } 99 | } 100 | 101 | // 获取当前selector 102 | SEL sel = NSSelectorFromString(invocation[dna_method]); 103 | 104 | // 处理获得当前所有参数 105 | NSArray *invocationArgs = invocation[dna_args]; 106 | NSMutableArray *absoluteArgs = [NSMutableArray array]; 107 | if (dna_isAvailable(invocationArgs)) { 108 | for (id arg in invocationArgs) { 109 | if ([arg isKindOfClass:NSDictionary.class] && dna_getObjectId(arg)) { 110 | // 如果含有_objectId, 根据_objectId得到实例 111 | id argInContext = objectsInContextMap[dna_getObjectId(arg)]; 112 | if (argInContext) { 113 | [absoluteArgs addObject:argInContext]; 114 | } 115 | } else { 116 | // channel 约定的基本类型,直接添加 117 | [absoluteArgs addObject:arg]; 118 | } 119 | } 120 | } 121 | 122 | // 当前Invocation的返回值_objectId; 123 | NSString *invocationReturnVarObjectId = dna_getObjectId(invocation[dna_returnVar]); 124 | 125 | // 执行Invocation; 126 | id invocationReturnVar = [object dna_performSelector:sel withObjects:absoluteArgs]; 127 | if (invocationReturnVar) { 128 | // 当前invocation有返回值,把返回值 返回值_objectId 加入到objectsInContextMap中 129 | objectsInContextMap[invocationReturnVarObjectId] = invocationReturnVar; 130 | if (!hasContextReturnVarFlag && (i == _invocationNodes.count - 1)) { 131 | // 如果context没有设置返回值_objectId,以最后一个invocation的返回值_objectId作为context 返回值_objectId 132 | contextReturnVarObjectId = invocationReturnVarObjectId; 133 | } 134 | } 135 | } 136 | 137 | id contextReturnValue = nil; 138 | if (contextReturnVarObjectId) { 139 | // 取得context的返回值 140 | contextReturnValue = objectsInContextMap[contextReturnVarObjectId]; 141 | } 142 | 143 | if (result) { 144 | // 回调给dart返回值 145 | result(contextReturnValue); 146 | } 147 | } 148 | 149 | NS_INLINE BOOL dna_isAvailable(id arg) { 150 | return arg && ![arg isKindOfClass:NSNull.class]; 151 | } 152 | 153 | NS_INLINE NSString *dna_getObjectId(NSDictionary *nativeVarJSON) { 154 | return nativeVarJSON[dna_objectId]; 155 | } 156 | 157 | @end 158 | -------------------------------------------------------------------------------- /ios/Classes/NSObject+DnaRuntime.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+DnaRuntime.h 3 | // LPDAdditionsKit 4 | // 5 | // Created by Assuner on 2018/4/13. 6 | // 7 | 8 | #import 9 | 10 | @interface NSObject (DnaRuntime) 11 | 12 | + (id)dna_objectWithBuffer:(void *)valueLoc type:(const char *)typeStr; 13 | - (void)dna_getValue:(void *)valueLoc type:(const char *)argType; // id / NSValue Type 14 | - (id)dna_performSelector:(SEL)aSelector withObjects:(NSArray *)objects; // id / NSValue Type 15 | 16 | @end 17 | 18 | @interface NSInvocation (DnaObjectParams) 19 | 20 | - (id)dna_getArgumentObjectAtIndex:(NSInteger)idx; 21 | - (void)dna_setArgumentObject:(id)arguementObject atIndex:(NSInteger)idx; 22 | 23 | @end 24 | 25 | -------------------------------------------------------------------------------- /ios/Classes/NSObject+DnaRuntime.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+DnaRuntime.m 3 | // LPDAdditionsKit 4 | // 5 | // Created by Assuner on 2018/4/13. 6 | // 7 | 8 | #import "NSObject+DnaRuntime.h" 9 | 10 | @implementation NSObject (DnaRuntime) 11 | 12 | + (id)dna_objectWithBuffer:(void *)valueLoc type:(const char *)argType { 13 | #define RETURN_WRAPPERED_OBJECT(type) \ 14 | do { \ 15 | type val = 0; \ 16 | val = *((type *) valueLoc); \ 17 | return @(val); \ 18 | } while(0); 19 | 20 | if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0 || strcmp(argType, @encode(void(^)(void))) == 0) { 21 | return *((__autoreleasing id *)valueLoc); 22 | } else if (strcmp(argType, @encode(char)) == 0) { 23 | RETURN_WRAPPERED_OBJECT(char); 24 | } else if (strcmp(argType, @encode(int)) == 0) { 25 | RETURN_WRAPPERED_OBJECT(int); 26 | } else if (strcmp(argType, @encode(short)) == 0) { 27 | RETURN_WRAPPERED_OBJECT(short); 28 | } else if (strcmp(argType, @encode(long)) == 0) { 29 | RETURN_WRAPPERED_OBJECT(long); 30 | } else if (strcmp(argType, @encode(long long)) == 0) { 31 | RETURN_WRAPPERED_OBJECT(long long); 32 | } else if (strcmp(argType, @encode(unsigned char)) == 0) { 33 | RETURN_WRAPPERED_OBJECT(unsigned char); 34 | } else if (strcmp(argType, @encode(unsigned int)) == 0) { 35 | RETURN_WRAPPERED_OBJECT(unsigned int); 36 | } else if (strcmp(argType, @encode(unsigned short)) == 0) { 37 | RETURN_WRAPPERED_OBJECT(unsigned short); 38 | } else if (strcmp(argType, @encode(unsigned long)) == 0) { 39 | RETURN_WRAPPERED_OBJECT(unsigned long); 40 | } else if (strcmp(argType, @encode(unsigned long long)) == 0) { 41 | RETURN_WRAPPERED_OBJECT(unsigned long long); 42 | } else if (strcmp(argType, @encode(float)) == 0) { 43 | RETURN_WRAPPERED_OBJECT(float); 44 | } else if (strcmp(argType, @encode(double)) == 0) { 45 | RETURN_WRAPPERED_OBJECT(double); 46 | } else if (strcmp(argType, @encode(BOOL)) == 0) { 47 | RETURN_WRAPPERED_OBJECT(BOOL); 48 | } else if (strcmp(argType, @encode(char *)) == 0) { 49 | RETURN_WRAPPERED_OBJECT(const char *); 50 | } else { 51 | return [NSValue valueWithBytes:valueLoc objCType:argType]; 52 | } 53 | } 54 | 55 | - (void)dna_getValue:(void *)valueLoc type:(const char *)argType { 56 | #define UNWRAPPER_AND_SET(type, selector) \ 57 | do { \ 58 | *((type *) valueLoc) = [(id)self selector];\ 59 | } while (0) 60 | 61 | if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0 || strcmp(argType, @encode(void(^)(void))) == 0) { 62 | *((__autoreleasing id *)valueLoc) = self; 63 | } else if (strcmp(argType, @encode(char)) == 0) { 64 | UNWRAPPER_AND_SET(char, charValue); 65 | } else if (strcmp(argType, @encode(int)) == 0) { 66 | UNWRAPPER_AND_SET(int, intValue); 67 | } else if (strcmp(argType, @encode(short)) == 0) { 68 | UNWRAPPER_AND_SET(short, shortValue); 69 | } else if (strcmp(argType, @encode(long)) == 0) { 70 | UNWRAPPER_AND_SET(long, longValue); 71 | } else if (strcmp(argType, @encode(long long)) == 0) { 72 | UNWRAPPER_AND_SET(long long, longLongValue); 73 | } else if (strcmp(argType, @encode(unsigned char)) == 0) { 74 | UNWRAPPER_AND_SET(unsigned char, unsignedCharValue); 75 | } else if (strcmp(argType, @encode(unsigned int)) == 0) { 76 | UNWRAPPER_AND_SET(unsigned int, unsignedIntValue); 77 | } else if (strcmp(argType, @encode(unsigned short)) == 0) { 78 | UNWRAPPER_AND_SET(unsigned short, unsignedShortValue); 79 | } else if (strcmp(argType, @encode(unsigned long)) == 0) { 80 | UNWRAPPER_AND_SET(unsigned long, unsignedLongValue); 81 | } else if (strcmp(argType, @encode(unsigned long long)) == 0) { 82 | UNWRAPPER_AND_SET(unsigned long long, unsignedLongLongValue); 83 | } else if (strcmp(argType, @encode(float)) == 0) { 84 | UNWRAPPER_AND_SET(float, floatValue); 85 | } else if (strcmp(argType, @encode(double)) == 0) { 86 | UNWRAPPER_AND_SET(double, doubleValue); 87 | } else if (strcmp(argType, @encode(BOOL)) == 0) { 88 | UNWRAPPER_AND_SET(BOOL, boolValue); 89 | } else if (strcmp(argType, @encode(char *)) == 0) { 90 | *((char **) valueLoc) = (char *)[(id)self UTF8String]; 91 | } else { 92 | [(NSValue *)self getValue:valueLoc]; 93 | } 94 | } 95 | 96 | - (id)dna_performSelector:(SEL)aSelector withObjects:(NSArray *)objects { 97 | NSMethodSignature *signature = [self methodSignatureForSelector:aSelector]; 98 | if (!signature || objects.count != signature.numberOfArguments - 2) { 99 | return nil; 100 | } 101 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 102 | for (NSInteger i = 0; i < objects.count; i ++) { 103 | [invocation dna_setArgumentObject:objects[i] atIndex:i+2]; 104 | } 105 | invocation.selector = aSelector; 106 | invocation.target = self; 107 | [invocation retainArguments]; 108 | [invocation invoke]; 109 | if (!signature.methodReturnLength) { 110 | return nil; 111 | } else { 112 | void *valueLoc = alloca(signature.methodReturnLength); 113 | [invocation getReturnValue:valueLoc]; 114 | return [NSObject dna_objectWithBuffer:valueLoc type:signature.methodReturnType]; 115 | } 116 | } 117 | 118 | @end 119 | 120 | 121 | @implementation NSInvocation (DnaObjectParams) 122 | 123 | - (id)dna_getArgumentObjectAtIndex:(NSInteger)idx { 124 | #define WRAP_AND_RETURN(type) \ 125 | do { \ 126 | type val = 0; \ 127 | [self getArgument:&val atIndex:idx]; \ 128 | return @(val); \ 129 | } while (0) 130 | 131 | const char *argType = [self.methodSignature getArgumentTypeAtIndex:idx]; 132 | if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) { 133 | __autoreleasing id returnObj; 134 | [self getArgument:&returnObj atIndex:idx]; 135 | return returnObj; 136 | } else if (strcmp(argType, @encode(char)) == 0) { 137 | WRAP_AND_RETURN(char); 138 | } else if (strcmp(argType, @encode(int)) == 0) { 139 | WRAP_AND_RETURN(int); 140 | } else if (strcmp(argType, @encode(short)) == 0) { 141 | WRAP_AND_RETURN(short); 142 | } else if (strcmp(argType, @encode(long)) == 0) { 143 | WRAP_AND_RETURN(long); 144 | } else if (strcmp(argType, @encode(long long)) == 0) { 145 | WRAP_AND_RETURN(long long); 146 | } else if (strcmp(argType, @encode(unsigned char)) == 0) { 147 | WRAP_AND_RETURN(unsigned char); 148 | } else if (strcmp(argType, @encode(unsigned int)) == 0) { 149 | WRAP_AND_RETURN(unsigned int); 150 | } else if (strcmp(argType, @encode(unsigned short)) == 0) { 151 | WRAP_AND_RETURN(unsigned short); 152 | } else if (strcmp(argType, @encode(unsigned long)) == 0) { 153 | WRAP_AND_RETURN(unsigned long); 154 | } else if (strcmp(argType, @encode(unsigned long long)) == 0) { 155 | WRAP_AND_RETURN(unsigned long long); 156 | } else if (strcmp(argType, @encode(float)) == 0) { 157 | WRAP_AND_RETURN(float); 158 | } else if (strcmp(argType, @encode(double)) == 0) { 159 | WRAP_AND_RETURN(double); 160 | } else if (strcmp(argType, @encode(BOOL)) == 0) { 161 | WRAP_AND_RETURN(BOOL); 162 | } else if (strcmp(argType, @encode(char *)) == 0) { 163 | WRAP_AND_RETURN(const char *); 164 | } else if (strcmp(argType, @encode(void (^)(void))) == 0) { 165 | __unsafe_unretained id block = nil; 166 | [self getArgument:&block atIndex:idx]; 167 | return [block copy]; 168 | } else { 169 | NSUInteger valueSize = 0; 170 | NSGetSizeAndAlignment(argType, &valueSize, NULL); 171 | unsigned char valueBytes[valueSize]; 172 | [self getArgument:valueBytes atIndex:idx]; 173 | return [NSValue valueWithBytes:valueBytes objCType:argType]; 174 | } 175 | } 176 | 177 | - (void)dna_setArgumentObject:(id)arguementObject atIndex:(NSInteger)idx { 178 | #define PULL_AND_SET(type, selector) \ 179 | do { \ 180 | type val = [arguementObject selector]; \ 181 | [self setArgument:&val atIndex:idx]; \ 182 | } while (0) 183 | if ([arguementObject isKindOfClass:NSNull.class]) { 184 | arguementObject = nil; 185 | } 186 | const char *argType = [self.methodSignature getArgumentTypeAtIndex:idx]; 187 | if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) { 188 | [self setArgument:&arguementObject atIndex:idx]; 189 | } else if (strcmp(argType, @encode(char)) == 0) { 190 | PULL_AND_SET(char, charValue); 191 | } else if (strcmp(argType, @encode(int)) == 0) { 192 | PULL_AND_SET(int, intValue); 193 | } else if (strcmp(argType, @encode(short)) == 0) { 194 | PULL_AND_SET(short, shortValue); 195 | } else if (strcmp(argType, @encode(long)) == 0) { 196 | PULL_AND_SET(long, longValue); 197 | } else if (strcmp(argType, @encode(long long)) == 0) { 198 | PULL_AND_SET(long long, longLongValue); 199 | } else if (strcmp(argType, @encode(unsigned char)) == 0) { 200 | PULL_AND_SET(unsigned char, unsignedCharValue); 201 | } else if (strcmp(argType, @encode(unsigned int)) == 0) { 202 | PULL_AND_SET(unsigned int, unsignedIntValue); 203 | } else if (strcmp(argType, @encode(unsigned short)) == 0) { 204 | PULL_AND_SET(unsigned short, unsignedShortValue); 205 | } else if (strcmp(argType, @encode(unsigned long)) == 0) { 206 | PULL_AND_SET(unsigned long, unsignedLongValue); 207 | } else if (strcmp(argType, @encode(unsigned long long)) == 0) { 208 | PULL_AND_SET(unsigned long long, unsignedLongLongValue); 209 | } else if (strcmp(argType, @encode(float)) == 0) { 210 | PULL_AND_SET(float, floatValue); 211 | } else if (strcmp(argType, @encode(double)) == 0) { 212 | PULL_AND_SET(double, doubleValue); 213 | } else if (strcmp(argType, @encode(BOOL)) == 0) { 214 | PULL_AND_SET(BOOL, boolValue); 215 | } else if (strcmp(argType, @encode(char *)) == 0) { 216 | const char *cString = [arguementObject UTF8String]; 217 | [self setArgument:&cString atIndex:idx]; 218 | [self retainArguments]; 219 | } else if (strcmp(argType, @encode(void (^)(void))) == 0) { 220 | [self setArgument:&arguementObject atIndex:idx]; 221 | } else { 222 | NSCParameterAssert([arguementObject isKindOfClass:NSValue.class]); 223 | NSUInteger valueSize = 0; 224 | NSGetSizeAndAlignment([arguementObject objCType], &valueSize, NULL); 225 | 226 | unsigned char valueBytes[valueSize]; 227 | [arguementObject getValue:valueBytes]; 228 | [self setArgument:valueBytes atIndex:idx]; 229 | } 230 | } 231 | 232 | 233 | @end 234 | -------------------------------------------------------------------------------- /ios/dna.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 = 'dna' 6 | s.version = '0.0.1' 7 | s.summary = 'A new flutter plugin project.' 8 | s.description = <<-DESC 9 | A new flutter plugin project. 10 | DESC 11 | s.homepage = 'http://example.com' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Your Company' => 'email@example.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 | 20 | s.ios.deployment_target = '8.0' 21 | end 22 | 23 | -------------------------------------------------------------------------------- /lib/dna.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/services.dart'; 3 | import 'dart:io'; 4 | import 'native_context.dart'; 5 | 6 | export 'native_context.dart' show NativeContext, ObjCContext, JAVAContext; 7 | export 'native_object.dart' show NativeObject, NativeClass; 8 | 9 | 10 | class Dna { 11 | static const MethodChannel _channel = 12 | const MethodChannel('dna'); 13 | 14 | static Future executeNativeContext(NativeContext context) async { 15 | return await _channel.invokeMethod('executeNativeContext', context.toJSON()); 16 | } 17 | 18 | static Future traversingNative( 19 | ObjCContextBuilder(ObjCContext objcContext), 20 | JAVAContextBuilder(JAVAContext javaContext)) async { 21 | NativeContext nativeContext; 22 | if (Platform.isIOS) { 23 | nativeContext = ObjCContext(); 24 | ObjCContextBuilder(nativeContext); 25 | } else if (Platform.isAndroid) { 26 | nativeContext = JAVAContext(); 27 | JAVAContextBuilder(nativeContext); 28 | } 29 | return executeNativeContext(nativeContext); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /lib/native_context.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dna.dart'; 3 | import 'native_object.dart'; 4 | 5 | class NativeInvocation { 6 | final NativeObject object; 7 | final String method; 8 | final List args; 9 | final NativeObject returnVar; 10 | 11 | NativeInvocation(this.object, this.method, this.args, this.returnVar); 12 | 13 | Map toJSON() { 14 | Map json = Map(); 15 | if (object != null) { 16 | json['object'] = object.toJSON(); 17 | } 18 | 19 | if (method != null) { 20 | json['method'] = method; 21 | } 22 | 23 | if (args != null) { 24 | List argsJSON = List(); 25 | for (var arg in args) { 26 | if (arg is NativeObject) { 27 | argsJSON.add(arg.toJSON()); 28 | } else { 29 | argsJSON.add(arg); 30 | } 31 | } 32 | json['args'] = argsJSON; 33 | } 34 | 35 | if (returnVar != null) { 36 | json['returnVar'] = returnVar.toJSON(); 37 | } 38 | return json; 39 | } 40 | } 41 | 42 | //////////////////////////////////////////////////////////////////////////// 43 | //////////////////////////////////////////////////////////////////////////// 44 | 45 | class NativeContext { 46 | final List _invocationNodes = List(); 47 | final List _objectJSONWrappers = List(); 48 | NativeObject returnVar; 49 | 50 | void invoke({NativeObject object, String method, List args, NativeObject returnVar}) { 51 | NativeInvocation invocation = NativeInvocation(object, method, args, returnVar); 52 | _invocationNodes.add(invocation); 53 | } 54 | 55 | NativeObject classFromString(String clsName) { 56 | NativeClass cls = NativeClass(this, clsName); 57 | return cls; 58 | } 59 | 60 | NativeObject newNativeObject() { 61 | NativeObject object = NativeObject(this); 62 | return object; 63 | } 64 | 65 | NativeObject newNativeObjectFromJSON(Map json, String cls) { 66 | NativeObject object = NativeObjectJSONWrapper(this, json, cls); 67 | _objectJSONWrappers.add(object); 68 | return object; 69 | } 70 | 71 | 72 | Map toJSON() { 73 | List invocationNodesJSON = List(); 74 | for (var invocation in _invocationNodes) { 75 | invocationNodesJSON.add(invocation.toJSON()); 76 | } 77 | 78 | List objectJSONWrappersJSON = List(); 79 | for (var jsonVar in _objectJSONWrappers) { 80 | objectJSONWrappersJSON.add(jsonVar.toJSON()); 81 | } 82 | 83 | Map json = Map(); 84 | json['_invocationNodes'] = invocationNodesJSON; 85 | json['_objectJSONWrappers'] = objectJSONWrappersJSON; 86 | 87 | if (returnVar != null) { 88 | json['returnVar'] = returnVar.toJSON(); 89 | } 90 | return json; 91 | } 92 | 93 | bool canExecute() { 94 | return false; 95 | } 96 | 97 | Future execute() async { 98 | if (this.canExecute()) { 99 | return await Dna.executeNativeContext(this); 100 | } else { 101 | return null; 102 | } 103 | } 104 | } 105 | 106 | 107 | ////////////////// 108 | class ObjCContext extends NativeContext { 109 | bool canExecute() { 110 | return Platform.isIOS; 111 | } 112 | } 113 | 114 | ////////////////// 115 | class JAVAContext extends NativeContext { 116 | bool canExecute() { 117 | return Platform.isAndroid; 118 | } 119 | 120 | NativeObject newJavaObjectFromConstructor(String clsName, List args) { 121 | NativeObject orignVar = JavaObjectConstructor(this, clsName, args); 122 | return orignVar; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /lib/native_object.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'native_context.dart'; 3 | 4 | class NativeObject extends Object { 5 | final NativeContext context; 6 | 7 | static String _alphabet = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'; 8 | static int _strlenght = 8; 9 | String _objectId; 10 | 11 | static String _randomString() { 12 | String randomString = ''; 13 | for (var i = 0; i < _strlenght; i++) { 14 | randomString = randomString + _alphabet[Random().nextInt(_alphabet.length)]; 15 | } 16 | return randomString; 17 | } 18 | 19 | NativeObject(this.context) { 20 | _objectId = '_objectId_' + _randomString(); 21 | } 22 | 23 | Map toJSON () { 24 | Map json = Map(); 25 | if (_objectId != null) { 26 | json['_objectId'] = _objectId; 27 | } 28 | return json; 29 | } 30 | 31 | NativeObject invoke({String method, List args}) { 32 | NativeObject returnValue = NativeObject(this.context); 33 | context.invoke(object: this, method: method, args: args, returnVar: returnValue); 34 | return returnValue; 35 | } 36 | } 37 | 38 | ////////////////// 39 | class NativeClass extends NativeObject { 40 | final String clsName; 41 | NativeClass(NativeContext context, this.clsName) : super(context); 42 | 43 | Map toJSON () { 44 | Map json = super.toJSON(); 45 | if (clsName != null) { 46 | json['clsName'] = clsName; 47 | } 48 | return json; 49 | } 50 | } 51 | 52 | ////////////////// 53 | class NativeObjectJSONWrapper extends NativeObject { 54 | final Map json; 55 | final String cls; 56 | NativeObjectJSONWrapper(NativeContext context, this.json, this.cls) : super(context); 57 | 58 | Map toJSON () { 59 | Map json = super.toJSON(); 60 | if (this.json != null) { 61 | json['json'] = this.json; 62 | } 63 | 64 | if (cls != null) { 65 | json['cls'] = cls; 66 | } 67 | return json; 68 | } 69 | } 70 | 71 | //////////////////// 72 | class JavaObjectConstructor extends NativeObject { 73 | final String cls; 74 | 75 | JavaObjectConstructor(NativeContext context, this.cls, List args) : super(context) { 76 | context.invoke(object: this, method: null, args: args, returnVar: this); 77 | } 78 | 79 | Map toJSON() { 80 | Map json = super.toJSON(); 81 | json['constructCls'] = cls; 82 | return json; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.1.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.4" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.2" 25 | collection: 26 | dependency: transitive 27 | description: 28 | name: collection 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.14.11" 32 | flutter: 33 | dependency: "direct main" 34 | description: flutter 35 | source: sdk 36 | version: "0.0.0" 37 | flutter_test: 38 | dependency: "direct dev" 39 | description: flutter 40 | source: sdk 41 | version: "0.0.0" 42 | matcher: 43 | dependency: transitive 44 | description: 45 | name: matcher 46 | url: "https://pub.dartlang.org" 47 | source: hosted 48 | version: "0.12.5" 49 | meta: 50 | dependency: transitive 51 | description: 52 | name: meta 53 | url: "https://pub.dartlang.org" 54 | source: hosted 55 | version: "1.1.6" 56 | path: 57 | dependency: transitive 58 | description: 59 | name: path 60 | url: "https://pub.dartlang.org" 61 | source: hosted 62 | version: "1.6.2" 63 | pedantic: 64 | dependency: transitive 65 | description: 66 | name: pedantic 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "1.5.0" 70 | quiver: 71 | dependency: transitive 72 | description: 73 | name: quiver 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "2.0.2" 77 | sky_engine: 78 | dependency: transitive 79 | description: flutter 80 | source: sdk 81 | version: "0.0.99" 82 | source_span: 83 | dependency: transitive 84 | description: 85 | name: source_span 86 | url: "https://pub.dartlang.org" 87 | source: hosted 88 | version: "1.5.5" 89 | stack_trace: 90 | dependency: transitive 91 | description: 92 | name: stack_trace 93 | url: "https://pub.dartlang.org" 94 | source: hosted 95 | version: "1.9.3" 96 | stream_channel: 97 | dependency: transitive 98 | description: 99 | name: stream_channel 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "2.0.0" 103 | string_scanner: 104 | dependency: transitive 105 | description: 106 | name: string_scanner 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.0.4" 110 | term_glyph: 111 | dependency: transitive 112 | description: 113 | name: term_glyph 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "1.1.0" 117 | test_api: 118 | dependency: transitive 119 | description: 120 | name: test_api 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "0.2.4" 124 | typed_data: 125 | dependency: transitive 126 | description: 127 | name: typed_data 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.1.6" 131 | vector_math: 132 | dependency: transitive 133 | description: 134 | name: vector_math 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "2.0.8" 138 | sdks: 139 | dart: ">=2.2.0 <3.0.0" 140 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dna 2 | description: A new flutter plugin project. 3 | version: 0.0.1 4 | author: 5 | homepage: 6 | 7 | environment: 8 | sdk: ">=2.1.0 <3.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter 17 | 18 | # For information on the generic Dart part of this file, see the 19 | # following page: https://www.dartlang.org/tools/pub/pubspec 20 | 21 | # The following section is specific to Flutter. 22 | flutter: 23 | # This section identifies this Flutter project as a plugin project. 24 | # The androidPackage and pluginClass identifiers should not ordinarily 25 | # be modified. They are used by the tooling to maintain consistency when 26 | # adding or updating assets for this project. 27 | plugin: 28 | androidPackage: me.ele.dna 29 | pluginClass: DnaPlugin 30 | 31 | # To add assets to your plugin package, add an assets section, like this: 32 | # assets: 33 | # - images/a_dot_burr.jpeg 34 | # - images/a_dot_ham.jpeg 35 | # 36 | # For details regarding assets in packages, see 37 | # https://flutter.dev/assets-and-images/#from-packages 38 | # 39 | # An image asset can refer to one or more resolution-specific "variants", see 40 | # https://flutter.dev/assets-and-images/#resolution-aware. 41 | 42 | # To add custom fonts to your plugin package, add a fonts section here, 43 | # in this "flutter" section. Each entry in this list should have a 44 | # "family" key with the font family name, and a "fonts" key with a 45 | # list giving the asset and other descriptors for the font. For 46 | # example: 47 | # fonts: 48 | # - family: Schyler 49 | # fonts: 50 | # - asset: fonts/Schyler-Regular.ttf 51 | # - asset: fonts/Schyler-Italic.ttf 52 | # style: italic 53 | # - family: Trajan Pro 54 | # fonts: 55 | # - asset: fonts/TrajanPro.ttf 56 | # - asset: fonts/TrajanPro_Bold.ttf 57 | # weight: 700 58 | # 59 | # For details regarding fonts in packages, see 60 | # https://flutter.dev/custom-fonts/#from-packages 61 | -------------------------------------------------------------------------------- /test/dna_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:dna/dna.dart'; 4 | 5 | void main() { 6 | const MethodChannel channel = MethodChannel('dna'); 7 | 8 | setUp(() { 9 | channel.setMockMethodCallHandler((MethodCall methodCall) async { 10 | return '42'; 11 | }); 12 | }); 13 | 14 | tearDown(() { 15 | channel.setMockMethodCallHandler(null); 16 | }); 17 | 18 | test('getPlatformVersion', () async { 19 | 20 | }); 21 | } 22 | --------------------------------------------------------------------------------