├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── build.gradle ├── gradle.properties ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── tvd12 │ └── ezyfoxserver │ └── client │ └── flutter │ ├── EzyClientProxy.java │ ├── EzyFlutterClientPlugin.java │ ├── EzyMethodNames.java │ ├── exception │ └── EzyMethodCallException.java │ ├── proxy │ ├── EzyConnectMethod.java │ ├── EzyCreateClientMethod.java │ ├── EzyDisconnectMethod.java │ ├── EzyGenerateKeyPairMethod.java │ ├── EzyLogMethod.java │ ├── EzyMethodProxy.java │ ├── EzyReconnectMethod.java │ ├── EzyRsaDecryptMethod.java │ ├── EzySendMethod.java │ ├── EzySetSessionKeyMethod.java │ ├── EzySetStatusMethod.java │ └── EzyStartPingScheduleMethod.java │ └── serializer │ ├── EzyClientConfigSerializer.java │ ├── EzyEventSerializer.java │ ├── EzyNativeDataDeserializer.java │ ├── EzyNativeDataSerializer.java │ └── EzyNativeSerializers.java ├── example ├── .gitignore ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── tvd12 │ │ │ │ │ └── hello_flutter │ │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── 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-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ └── settings.gradle ├── images │ └── flutter-sdk.png ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── 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 │ │ ├── Runner-Bridging-Header.h │ │ └── main.m ├── lib │ ├── main.dart │ └── socket_proxy.dart └── pubspec.yaml ├── images └── flutter-sdk.png ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── EzyClient │ ├── EzyClientProxy.h │ ├── EzyClientProxy.mm │ ├── EzyFlutterClientPlugin.h │ ├── EzyFlutterClientPlugin.m │ ├── EzyMethodNames.h │ ├── EzyMethodNames.mm │ ├── Prefix.pch │ ├── codec │ │ ├── EzyEncryptionProxy.h │ │ └── EzyEncryptionProxy.mm │ ├── exception │ │ ├── EzyMethodCallException.h │ │ └── EzyMethodCallException.mm │ ├── math │ │ ├── EzyNSNumber.h │ │ └── EzyNSNumber.m │ ├── proxy │ │ ├── EzyMethodProxy.h │ │ └── EzyMethodProxy.mm │ ├── serializer │ │ ├── EzyClientConfigSerializer.h │ │ ├── EzyClientConfigSerializer.mm │ │ ├── EzyEventSerializer.h │ │ ├── EzyEventSerializer.mm │ │ ├── EzyNativeDataDeserializer.h │ │ ├── EzyNativeDataDeserializer.mm │ │ ├── EzyNativeDataSerializer.h │ │ ├── EzyNativeDataSerializer.mm │ │ ├── EzyNativeSerializers.h │ │ └── EzyNativeSerializers.mm │ └── util │ │ ├── EzyNativeStrings.h │ │ ├── EzyNativeStrings.mm │ │ ├── NSByArray.m │ │ └── NSByteArray.h └── ezyfox_server_flutter_client.podspec ├── lib ├── ezy_client.dart ├── ezy_clients.dart ├── ezy_codec.dart ├── ezy_config.dart ├── ezy_constants.dart ├── ezy_entities.dart ├── ezy_handlers.dart ├── ezy_logger.dart ├── ezy_managers.dart ├── ezy_proxy.dart ├── ezy_setup.dart └── ezy_util.dart ├── pubspec.yaml └── test └── ezyfox_server_flutter_client_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | gradle/ 2 | */gradle/ 3 | **/gradle/ 4 | 5 | .iml 6 | *.iml 7 | 8 | .lock 9 | *.lock 10 | .idea/ 11 | */.idea/ 12 | **/.idea/ 13 | .metadata 14 | *.metadata 15 | 16 | .DS_Store 17 | .dart_tool/ 18 | 19 | .packages 20 | .pub/ 21 | 22 | build/ 23 | */build/ 24 | **/build/ 25 | logs/ 26 | */logs/ 27 | **/logs/ 28 | bin/ 29 | */bin/ 30 | **/bin/ 31 | .project 32 | */.project 33 | **/.project 34 | .classpath 35 | */.classpath 36 | **/.classpath 37 | .settings/ 38 | */.settings/ 39 | **/.settings/ 40 | 41 | obj/ 42 | */obj/ 43 | **/obj/ 44 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cpp-client-sdk"] 2 | path = ios/EzyClient/socket 3 | url = https://github.com/youngmonkeys/ezyfox-server-cpp-client.git 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | * Send and receive message 4 | * SSL encryption 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ezyfox-server-flutter-client 2 | 3 | flutter client for [ezyfox server](https://github.com/youngmonkeys/ezyfox-server) 4 | 5 | # Architecture 6 | 7 | 8 | 9 | # Official documentation 10 | 11 | [https://youngmonkeys.org/ezyfox-flutter-client-sdk/](https://youngmonkeys.org/ezyfox-flutter-client-sdk/) 12 | 13 | # Prepare 14 | 15 | 1. Download and install [JDK 8](https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html) 16 | 2. Download and install [Android Studio](https://developer.android.com/studio) 17 | 3. Download and install [Xcode](https://developer.apple.com/xcode) 18 | 4. Download and install [Intellij and Flutter plugin](https://www.jetbrains.com/idea/download) 19 | 5. Download and install [Flutter SDK](https://flutter.dev/docs/get-started/install) 20 | 21 | # How to test? 22 | 23 | ### 1. Clone source code 24 | 25 | ``` 26 | git clone --recurse-submodules https://github.com/youngmonkeys/ezyfox-server-flutter-client.git ezyfox_server_flutter_client 27 | ``` 28 | 29 | ### 2. Import source code 30 | 31 | You need import `ezyfox_server_flutter_client/example` to your IDEs 32 | 33 | - To IntelliJ IDE: for all 34 | - To Xcode: for iOS 35 | - To Android studio: for Android 36 | 37 | ### 3. You can run 38 | 39 | - [main.dart](https://github.com/youngmonkeys/ezyfox-server-flutter-client/blob/master/example/lib/main.dart) on Intellij 40 | - Build and Run on Xcode for iOS, don't for get run `pod install` 41 | - Build and run on Android Studio for Android 42 | 43 | ### 4. Where need I click? 44 | 45 | - Tap to plus button in bottom right corner 46 | - When you see `Greet Flutter's developer!`, congratulation, you've just run and connect to server successfully 47 | 48 | # Contact us 49 | 50 | - Touch us on [Facebook](https://www.facebook.com/youngmonkeys.org) 51 | - Ask us on [stackask.com](https://stackask.com) 52 | - Email to me [Dzung](mailto:itprono3@gmail.com) -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | import java.nio.file.Paths 2 | 3 | group 'com.tvd12' 4 | version '1.0' 5 | 6 | buildscript { 7 | repositories { 8 | google() 9 | mavenCentral() 10 | } 11 | } 12 | 13 | rootProject.allprojects { 14 | repositories { 15 | google() 16 | mavenCentral() 17 | } 18 | } 19 | 20 | apply plugin: 'com.android.library' 21 | 22 | android { 23 | compileSdkVersion 31 24 | 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | 30 | defaultConfig { 31 | minSdkVersion 25 32 | } 33 | } 34 | 35 | def localProperties = new Properties() 36 | def localPropertiesFile = rootProject.file('local.properties') 37 | if (localPropertiesFile.exists()) { 38 | localPropertiesFile.withReader('UTF-8') { reader -> 39 | localProperties.load(reader) 40 | } 41 | } 42 | 43 | def flutterRoot = localProperties.getProperty('flutter.sdk') 44 | if (flutterRoot == null) { 45 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 46 | } 47 | 48 | String engineVersion = Paths 49 | .get(flutterRoot, "bin", "internal", "engine.version") 50 | .toFile() 51 | .text.trim() 52 | 53 | dependencies { 54 | implementation("com.tvd12:ezyfox-server-android-client:1.0.5") 55 | compileOnly("androidx.core:core:1.1.0") 56 | compileOnly("io.flutter:flutter_embedding_debug:1.0.0-$engineVersion") 57 | } 58 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'ezyfox_server_flutter_client' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/EzyClientProxy.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter; 2 | 3 | import android.util.Log; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | import com.tvd12.ezyfoxserver.client.flutter.exception.EzyMethodCallException; 8 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzyConnectMethod; 9 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzyCreateClientMethod; 10 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzyDisconnectMethod; 11 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzyGenerateKeyPairMethod; 12 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzyLogMethod; 13 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzyMethodProxy; 14 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzyReconnectMethod; 15 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzyRsaDecryptMethod; 16 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzySendMethod; 17 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzySetSessionKeyMethod; 18 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzySetStatusMethod; 19 | import com.tvd12.ezyfoxserver.client.flutter.proxy.EzyStartPingScheduleMethod; 20 | import com.tvd12.ezyfoxserver.client.socket.EzyMainEventsLoop; 21 | 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | 26 | import io.flutter.plugin.common.BinaryMessenger; 27 | import io.flutter.plugin.common.MethodCall; 28 | import io.flutter.plugin.common.MethodChannel; 29 | 30 | public class EzyClientProxy { 31 | 32 | private MethodChannel methodChannel; 33 | private final AtomicBoolean registered; 34 | private final Map methods; 35 | private final EzyMainEventsLoop mainEventsLoop; 36 | 37 | public static final String CHANNEL = "com.tvd12.ezyfoxserver.client"; 38 | private static final EzyClientProxy INSTANCE = new EzyClientProxy(); 39 | 40 | private EzyClientProxy() { 41 | this.methods = new HashMap<>(); 42 | this.registered = new AtomicBoolean(false); 43 | this.mainEventsLoop = new EzyMainEventsLoop(); 44 | } 45 | 46 | public static EzyClientProxy getInstance() { 47 | return INSTANCE; 48 | } 49 | 50 | public void register(BinaryMessenger messenger) { 51 | if(registered.compareAndSet(false, true)) { 52 | doRegister(messenger); 53 | } 54 | } 55 | 56 | public void unregister() { 57 | if(methodChannel != null) { 58 | methodChannel.setMethodCallHandler(null); 59 | } 60 | } 61 | 62 | private void doRegister(BinaryMessenger messenger) { 63 | methodChannel = new MethodChannel( 64 | messenger, 65 | CHANNEL 66 | ); 67 | methodChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() { 68 | @Override 69 | public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { 70 | EzyClientProxy.this.run(call.method, (Map) call.arguments, result); 71 | } 72 | }); 73 | this.addDefaultMethods(); 74 | this.mainEventsLoop.start(); 75 | } 76 | 77 | public void run(String method, Map params, MethodChannel.Result callback) { 78 | EzyMethodProxy func = methods.get(method); 79 | if(func == null) 80 | throw new IllegalArgumentException("has no method: " + method); 81 | try { 82 | func.validate(params); 83 | Object result = func.invoke(params); 84 | callback.success(result); 85 | } 86 | catch (EzyMethodCallException e) { 87 | if(callback != null) { 88 | Log.w("ezyfox-client", "call method: " + method + " with params: " + params + " error: " + e.getMessage()); 89 | callback.error(e.getCode(), e.getMessage(), e.toString()); 90 | } 91 | } 92 | catch (Exception e) { 93 | Log.e("ezyfox-client", "fatal error when call method: " + method, e); 94 | } 95 | } 96 | 97 | private void addDefaultMethods() { 98 | addMethod(new EzyCreateClientMethod(methodChannel)); 99 | addMethod(new EzyConnectMethod()); 100 | addMethod(new EzyReconnectMethod()); 101 | addMethod(new EzyDisconnectMethod()); 102 | addMethod(new EzySendMethod()); 103 | addMethod(new EzySetStatusMethod()); 104 | addMethod(new EzyStartPingScheduleMethod()); 105 | addMethod(new EzyGenerateKeyPairMethod()); 106 | addMethod(new EzyRsaDecryptMethod()); 107 | addMethod(new EzyLogMethod()); 108 | addMethod(new EzySetSessionKeyMethod()); 109 | } 110 | 111 | private void addMethod(EzyMethodProxy method) { 112 | methods.put(method.getName(), method); 113 | } 114 | } -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/EzyFlutterClientPlugin.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import io.flutter.embedding.engine.plugins.FlutterPlugin; 6 | 7 | public class EzyFlutterClientPlugin implements FlutterPlugin { 8 | 9 | @Override 10 | public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { 11 | EzyClientProxy.getInstance().register( 12 | flutterPluginBinding.getBinaryMessenger() 13 | ); 14 | } 15 | 16 | @Override 17 | public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { 18 | EzyClientProxy.getInstance().unregister(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/EzyMethodNames.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter; 2 | 3 | /** 4 | * Created by tavandung12 on 10/24/18. 5 | */ 6 | 7 | public final class EzyMethodNames { 8 | 9 | public static final String METHOD_INIT = "init"; 10 | public static final String METHOD_CONNECT = "connect"; 11 | public static final String METHOD_DISCONNECT = "disconnect"; 12 | public static final String METHOD_SEND = "send"; 13 | public static final String METHOD_RECONNECT = "reconnect"; 14 | public static final String METHOD_SET_STATUS = "setStatus"; 15 | public static final String METHOD_START_PING_SCHEDULE = "startPingSchedule"; 16 | public static final String METHOD_GENERATE_KEY_PAIR = "generateKeyPair"; 17 | public static final String METHOD_RSA_DECRYPT = "rsaDecrypt"; 18 | public static final String METHOD_LOG = "log"; 19 | public static final String METHOD_SET_SESSION_KEY = "setSessionKey"; 20 | 21 | private EzyMethodNames() { 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/exception/EzyMethodCallException.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.exception; 2 | 3 | /** 4 | * Created by tavandung12 on 10/24/18. 5 | */ 6 | 7 | public class EzyMethodCallException extends RuntimeException { 8 | private final String code; 9 | private final String message; 10 | 11 | public EzyMethodCallException(String code, String message) { 12 | super(message); 13 | this.code = code; 14 | this.message = message; 15 | } 16 | 17 | public EzyMethodCallException(String code, String message, Throwable ex) { 18 | super(message, ex); 19 | this.code = code; 20 | this.message = message; 21 | } 22 | 23 | public String getCode() { 24 | return code; 25 | } 26 | 27 | @Override 28 | public String getMessage() { 29 | return message; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzyConnectMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 4 | import com.tvd12.ezyfoxserver.client.EzyClient; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by tavandung12 on 10/24/18. 10 | */ 11 | 12 | public class EzyConnectMethod extends EzyMethodProxy { 13 | 14 | @Override 15 | public void validate(Map params) { 16 | if(!params.containsKey("host")) 17 | throw new IllegalArgumentException("must specific host"); 18 | if(!params.containsKey("port")) 19 | throw new IllegalArgumentException("must specific port"); 20 | } 21 | 22 | @Override 23 | public Object invoke(Map params) { 24 | String host = (String) params.get("host"); 25 | int port = (int) params.get("port"); 26 | EzyClient client = getClient(params); 27 | client.connect(host, port); 28 | return Boolean.TRUE; 29 | } 30 | 31 | @Override 32 | public String getName() { 33 | return EzyMethodNames.METHOD_CONNECT; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzyCreateClientMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.config.EzyPingConfig; 4 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 5 | import com.tvd12.ezyfoxserver.client.flutter.serializer.EzyNativeSerializers; 6 | import com.tvd12.ezyfoxserver.client.EzyClient; 7 | import com.tvd12.ezyfoxserver.client.setup.EzySetup; 8 | import com.tvd12.ezyfoxserver.client.config.EzyClientConfig; 9 | import com.tvd12.ezyfoxserver.client.config.EzyReconnectConfig; 10 | import com.tvd12.ezyfoxserver.client.constant.EzyCommand; 11 | import com.tvd12.ezyfoxserver.client.constant.EzyConstant; 12 | import com.tvd12.ezyfoxserver.client.entity.EzyArray; 13 | import com.tvd12.ezyfoxserver.client.event.EzyEvent; 14 | import com.tvd12.ezyfoxserver.client.event.EzyEventType; 15 | import com.tvd12.ezyfoxserver.client.handler.EzyDataHandler; 16 | import com.tvd12.ezyfoxserver.client.handler.EzyEventHandler; 17 | 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | import io.flutter.plugin.common.MethodChannel; 23 | 24 | /** 25 | * Created by tavandung12 on 10/24/18. 26 | */ 27 | 28 | public class EzyCreateClientMethod extends EzyMethodProxy { 29 | 30 | private final MethodChannel methodChannel; 31 | 32 | public EzyCreateClientMethod(MethodChannel methodChannel) { 33 | this.methodChannel = methodChannel; 34 | } 35 | 36 | @Override 37 | public void validate(Map params) { 38 | if(params == null) 39 | throw new NullPointerException("the config is null, can't create an client"); 40 | if(!params.containsKey("zoneName")) 41 | throw new IllegalArgumentException("must specific zone name"); 42 | } 43 | 44 | @Override 45 | public Object invoke(Map params) { 46 | EzyClientConfig config = newConfig(params); 47 | EzyClient client = getClient(config.getClientName()); 48 | if(client == null) { 49 | client = clients.newClient(config); 50 | setupClient(client); 51 | } 52 | Map configMap = EzyNativeSerializers.serialize(config); 53 | return configMap; 54 | } 55 | 56 | private EzyClientConfig newConfig(Map params) { 57 | EzyClientConfig.Builder configBuilder = EzyClientConfig.builder(); 58 | if(params.containsKey("clientName")) 59 | configBuilder.clientName((String) params.get("clientName")); 60 | if(params.containsKey("zoneName")) 61 | configBuilder.zoneName((String) params.get("zoneName")); 62 | if(params.containsKey("enableSSL")) 63 | configBuilder.enableSSL((Boolean) params.get("enableSSL")); 64 | if(params.containsKey("enableDebug")) 65 | configBuilder.enableDebug((Boolean) params.get("enableDebug")); 66 | if(params.containsKey("ping")) { 67 | Map ping = (Map) params.get("ping"); 68 | EzyPingConfig.Builder pingConfigBuilder = configBuilder.pingConfigBuilder(); 69 | if(ping.containsKey("pingPeriod")) 70 | pingConfigBuilder.pingPeriod((Integer) ping.get("pingPeriod")); 71 | if(ping.containsKey("maxLostPingCount")) 72 | pingConfigBuilder.maxLostPingCount((Integer) ping.get("maxLostPingCount")); 73 | } 74 | if(params.containsKey("reconnect")) { 75 | Map reconnect = (Map) params.get("reconnect"); 76 | EzyReconnectConfig.Builder reconnectConfigBuilder = configBuilder.reconnectConfigBuilder(); 77 | if (reconnect.containsKey("enable")) 78 | reconnectConfigBuilder.enable((Boolean) reconnect.get("enable")); 79 | if (reconnect.containsKey("reconnectPeriod")) 80 | reconnectConfigBuilder.reconnectPeriod((Integer) reconnect.get("reconnectPeriod")); 81 | if (reconnect.containsKey("maxReconnectCount")) 82 | reconnectConfigBuilder.maxReconnectCount((Integer) reconnect.get("maxReconnectCount")); 83 | } 84 | EzyClientConfig config = configBuilder.build(); 85 | return config; 86 | } 87 | 88 | public void setupClient(EzyClient client) { 89 | EzySetup setup = client.setup(); 90 | for(EzyEventType eventType : EzyEventType.values()) 91 | setup.addEventHandler(eventType, new EzyNativeEventHandler(client, methodChannel)); 92 | for(EzyCommand command : EzyCommand.values()) 93 | setup.addDataHandler(command, new EzyNativeDataHandler(client, methodChannel, command)); 94 | } 95 | 96 | @Override 97 | public String getName() { 98 | return EzyMethodNames.METHOD_INIT; 99 | } 100 | } 101 | 102 | class EzyNativeEventHandler implements EzyEventHandler { 103 | private final EzyClient client; 104 | private final MethodChannel methodChannel; 105 | 106 | public EzyNativeEventHandler(EzyClient client, MethodChannel methodChannel) { 107 | this.client = client; 108 | this.methodChannel = methodChannel; 109 | } 110 | 111 | @Override 112 | public void handle(EzyEvent event) { 113 | String eventTypeName = event.getType().getName(); 114 | Map params = new HashMap<>(); 115 | Map eventData = EzyNativeSerializers.serialize(event); 116 | params.put("clientName", client.getName()); 117 | params.put("eventType", eventTypeName); 118 | params.put("data", eventData); 119 | methodChannel.invokeMethod("ezy.event", params); 120 | } 121 | } 122 | 123 | class EzyNativeDataHandler implements EzyDataHandler { 124 | private final EzyClient client; 125 | private final MethodChannel methodChannel; 126 | private final EzyConstant command; 127 | 128 | public EzyNativeDataHandler(EzyClient client, 129 | MethodChannel methodChannel, 130 | EzyConstant command) { 131 | this.client = client; 132 | this.methodChannel = methodChannel; 133 | this.command = command; 134 | } 135 | 136 | @Override 137 | public void handle(EzyArray data) { 138 | String commandName = command.getName(); 139 | Map params = new HashMap<>(); 140 | List commandData = EzyNativeSerializers.toList(data); 141 | params.put("clientName", client.getName()); 142 | params.put("command", commandName); 143 | params.put("data", commandData); 144 | methodChannel.invokeMethod("ezy.data", params); 145 | } 146 | } -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzyDisconnectMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 4 | import com.tvd12.ezyfoxserver.client.EzyClient; 5 | import com.tvd12.ezyfoxserver.client.constant.EzyDisconnectReason; 6 | 7 | import java.util.Map; 8 | 9 | public class EzyDisconnectMethod extends EzyMethodProxy { 10 | 11 | @Override 12 | public Object invoke(Map params) { 13 | EzyClient client = getClient(params); 14 | int reason = EzyDisconnectReason.CLOSE.getId(); 15 | if(params.containsKey("reason")) 16 | reason = (int) params.get("reason"); 17 | client.disconnect(reason); 18 | return Boolean.TRUE; 19 | } 20 | 21 | @Override 22 | public String getName() { 23 | return EzyMethodNames.METHOD_DISCONNECT; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzyGenerateKeyPairMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import android.util.Base64; 4 | 5 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 6 | import com.tvd12.ezyfoxserver.client.security.EzyKeysGenerator; 7 | 8 | import java.security.KeyPair; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * Created by tavandung12 on 10/25/18. 14 | */ 15 | 16 | public class EzyGenerateKeyPairMethod extends EzyMethodProxy { 17 | @Override 18 | public Object invoke(Map params) { 19 | KeyPair keyPair = EzyKeysGenerator.builder() 20 | .build() 21 | .generate(); 22 | byte[] publicKey = keyPair.getPublic().getEncoded(); 23 | byte[] privateKey = keyPair.getPrivate().getEncoded(); 24 | Map answer = new HashMap<>(); 25 | answer.put("publicKey", Base64.encodeToString(publicKey, Base64.NO_WRAP)); 26 | answer.put("privateKey", privateKey); 27 | return answer; 28 | } 29 | 30 | @Override 31 | public String getName() { 32 | return EzyMethodNames.METHOD_GENERATE_KEY_PAIR; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzyLogMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 4 | import com.tvd12.ezyfoxserver.client.logger.EzyLogger; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by tavandung12 on 10/25/18. 10 | */ 11 | 12 | public class EzyLogMethod extends EzyMethodProxy { 13 | @Override 14 | public Object invoke(Map params) throws Exception { 15 | String level = (String)params.getOrDefault("level", "i"); 16 | String message = (String)params.get("message"); 17 | if(level.equals("w")) { 18 | EzyLogger.warn(message); 19 | } 20 | else if(level.equals("e")) { 21 | EzyLogger.error(message); 22 | } 23 | else if(level.equals("d")) { 24 | EzyLogger.debug(message); 25 | } 26 | else { 27 | EzyLogger.info(message); 28 | } 29 | return Boolean.TRUE; 30 | } 31 | 32 | @Override 33 | public String getName() { 34 | return EzyMethodNames.METHOD_LOG; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzyMethodProxy.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.EzyClient; 4 | import com.tvd12.ezyfoxserver.client.EzyClients; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by tavandung12 on 10/24/18. 10 | */ 11 | 12 | public abstract class EzyMethodProxy { 13 | 14 | protected EzyClients clients = EzyClients.getInstance(); 15 | 16 | public abstract Object invoke(Map params) throws Exception; 17 | public abstract String getName(); 18 | 19 | public void validate(Map params) {} 20 | 21 | protected EzyClient getClient(String name) { 22 | EzyClient client = clients.getClient(name); 23 | return client; 24 | } 25 | 26 | protected EzyClient getClient(Map params) { 27 | if(!params.containsKey("clientName")) 28 | throw new IllegalArgumentException("must specific client name"); 29 | String clientName = (String)params.get("clientName"); 30 | EzyClient client = getClient(clientName); 31 | return client; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzyReconnectMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 4 | import com.tvd12.ezyfoxserver.client.EzyClient; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by tavandung12 on 10/25/18. 10 | */ 11 | 12 | public class EzyReconnectMethod extends EzyMethodProxy { 13 | @Override 14 | public Object invoke(Map params) { 15 | EzyClient client = getClient(params); 16 | boolean answer = client.reconnect(); 17 | return answer; 18 | } 19 | 20 | @Override 21 | public String getName() { 22 | return EzyMethodNames.METHOD_RECONNECT; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzyRsaDecryptMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 4 | import com.tvd12.ezyfoxserver.client.security.EzyAsyCrypt; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by tavandung12 on 10/25/18. 10 | */ 11 | 12 | public class EzyRsaDecryptMethod extends EzyMethodProxy { 13 | @Override 14 | public Object invoke(Map params) throws Exception { 15 | byte[] message = (byte[])params.get("message"); 16 | byte[] privateKey = (byte[])params.get("privateKey"); 17 | return EzyAsyCrypt.builder() 18 | .privateKey(privateKey) 19 | .build() 20 | .decrypt(message); 21 | } 22 | 23 | @Override 24 | public String getName() { 25 | return EzyMethodNames.METHOD_RSA_DECRYPT; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzySendMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 4 | import com.tvd12.ezyfoxserver.client.flutter.serializer.EzyNativeSerializers; 5 | import com.tvd12.ezyfoxserver.client.EzyClient; 6 | import com.tvd12.ezyfoxserver.client.constant.EzyCommand; 7 | import com.tvd12.ezyfoxserver.client.entity.EzyArray; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * Created by tavandung12 on 10/25/18. 14 | */ 15 | 16 | public class EzySendMethod extends EzyMethodProxy { 17 | @Override 18 | public void validate(Map params) { 19 | if(!params.containsKey("request")) 20 | throw new IllegalArgumentException("must specific request to send to server"); 21 | } 22 | 23 | @Override 24 | public Object invoke(Map params) { 25 | EzyClient client = getClient(params); 26 | Map request = (Map) params.get("request"); 27 | String cmd = (String) request.get("command"); 28 | List data = (List) request.get("data"); 29 | boolean encrypted = (Boolean)request.getOrDefault("encrypted", false); 30 | EzyArray array = EzyNativeSerializers.fromList(data); 31 | client.send(EzyCommand.valueOf(cmd), array, encrypted); 32 | return Boolean.TRUE; 33 | } 34 | 35 | @Override 36 | public String getName() { 37 | return EzyMethodNames.METHOD_SEND; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzySetSessionKeyMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 4 | import com.tvd12.ezyfoxserver.client.EzyClient; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by tavandung12 on 10/25/18. 10 | */ 11 | 12 | public class EzySetSessionKeyMethod extends EzyMethodProxy { 13 | @Override 14 | public Object invoke(Map params) throws Exception { 15 | EzyClient client = getClient(params); 16 | byte[] sessionKey = (byte[])params.get("sessionKey"); 17 | client.setSessionKey(sessionKey); 18 | return Boolean.TRUE; 19 | } 20 | 21 | @Override 22 | public String getName() { 23 | return EzyMethodNames.METHOD_SET_SESSION_KEY; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzySetStatusMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 4 | import com.tvd12.ezyfoxserver.client.EzyClient; 5 | import com.tvd12.ezyfoxserver.client.constant.EzyConnectionStatus; 6 | 7 | import java.util.Map; 8 | 9 | /** 10 | * Created by tavandung12 on 10/25/18. 11 | */ 12 | 13 | public class EzySetStatusMethod extends EzyMethodProxy { 14 | @Override 15 | public Object invoke(Map params) { 16 | EzyClient client = getClient(params); 17 | String statusName = (String) params.get("status"); 18 | client.setStatus(EzyConnectionStatus.valueOf(statusName)); 19 | return Boolean.TRUE; 20 | } 21 | 22 | @Override 23 | public String getName() { 24 | return EzyMethodNames.METHOD_SET_STATUS; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/proxy/EzyStartPingScheduleMethod.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.proxy; 2 | 3 | import com.tvd12.ezyfoxserver.client.flutter.EzyMethodNames; 4 | import com.tvd12.ezyfoxserver.client.EzyClient; 5 | import com.tvd12.ezyfoxserver.client.socket.EzyPingSchedule; 6 | 7 | import java.util.Map; 8 | 9 | /** 10 | * Created by tavandung12 on 10/25/18. 11 | */ 12 | 13 | public class EzyStartPingScheduleMethod extends EzyMethodProxy { 14 | @Override 15 | public Object invoke(Map params) { 16 | EzyClient client = getClient(params); 17 | EzyPingSchedule pingSchedule = client.getPingSchedule(); 18 | pingSchedule.start(); 19 | return Boolean.TRUE; 20 | } 21 | 22 | @Override 23 | public String getName() { 24 | return EzyMethodNames.METHOD_START_PING_SCHEDULE; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/serializer/EzyClientConfigSerializer.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.serializer; 2 | 3 | import com.tvd12.ezyfoxserver.client.config.EzyClientConfig; 4 | import com.tvd12.ezyfoxserver.client.config.EzyPingConfig; 5 | import com.tvd12.ezyfoxserver.client.config.EzyReconnectConfig; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * Created by tavandung12 on 10/25/18. 12 | */ 13 | 14 | public class EzyClientConfigSerializer { 15 | 16 | public Map serialize(EzyClientConfig config) { 17 | Map map = new HashMap<>(); 18 | map.put("clientName", config.getClientName()); 19 | map.put("zoneName", config.getZoneName()); 20 | 21 | EzyPingConfig pingConfig = config.getPing(); 22 | Map pingMap = new HashMap<>(); 23 | pingMap.put("maxLostPingCount", pingConfig.getMaxLostPingCount()); 24 | pingMap.put("pingPeriod", pingConfig.getPingPeriod()); 25 | map.put("ping", pingMap); 26 | 27 | 28 | EzyReconnectConfig reconnectConfig = config.getReconnect(); 29 | Map reconnectMap = new HashMap<>(); 30 | reconnectMap.put("maxReconnectCount", reconnectConfig.getMaxReconnectCount()); 31 | reconnectMap.put("reconnectPeriod", reconnectConfig.getReconnectPeriod()); 32 | reconnectMap.put("enable", reconnectConfig.isEnable()); 33 | map.put("reconnect", reconnectMap); 34 | return map; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/serializer/EzyEventSerializer.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.serializer; 2 | 3 | import com.tvd12.ezyfoxserver.client.event.EzyConnectionFailureEvent; 4 | import com.tvd12.ezyfoxserver.client.event.EzyDisconnectionEvent; 5 | import com.tvd12.ezyfoxserver.client.event.EzyEvent; 6 | import com.tvd12.ezyfoxserver.client.event.EzyEventType; 7 | import com.tvd12.ezyfoxserver.client.event.EzyLostPingEvent; 8 | import com.tvd12.ezyfoxserver.client.event.EzyTryConnectEvent; 9 | import com.tvd12.ezyfoxserver.client.function.EzyFunction; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * Created by tavandung12 on 10/25/18. 16 | */ 17 | 18 | public class EzyEventSerializer { 19 | 20 | private final Map> appliers; 21 | 22 | public EzyEventSerializer() { 23 | this.appliers = newAppliers(); 24 | } 25 | 26 | public Map serialize(EzyEvent event) { 27 | EzyEventType eventType = event.getType(); 28 | EzyFunction func = getApplier(eventType); 29 | Map answer = func.apply(event); 30 | return answer; 31 | } 32 | 33 | private EzyFunction getApplier(EzyEventType eventType) { 34 | if(appliers.containsKey(eventType)) 35 | return appliers.get(eventType); 36 | throw new IllegalArgumentException("has no serializer for event type: " + eventType); 37 | } 38 | 39 | private Map> newAppliers() { 40 | Map> answer = new HashMap<>(); 41 | answer.put(EzyEventType.CONNECTION_SUCCESS, new EzyFunction() { 42 | @Override 43 | public Map apply(EzyEvent event) { 44 | return new HashMap<>(); 45 | } 46 | }); 47 | answer.put(EzyEventType.CONNECTION_FAILURE, new EzyFunction() { 48 | @Override 49 | public Map apply(EzyEvent event) { 50 | EzyConnectionFailureEvent mevent = (EzyConnectionFailureEvent)event; 51 | Map map = new HashMap<>(); 52 | map.put("reason", mevent.getReason().getId()); 53 | return map; 54 | } 55 | }); 56 | answer.put(EzyEventType.DISCONNECTION, new EzyFunction() { 57 | @Override 58 | public Map apply(EzyEvent event) { 59 | EzyDisconnectionEvent mevent = (EzyDisconnectionEvent)event; 60 | Map map = new HashMap<>(); 61 | map.put("reason", mevent.getReason()); 62 | return map; 63 | } 64 | }); 65 | answer.put(EzyEventType.LOST_PING, new EzyFunction() { 66 | @Override 67 | public Map apply(EzyEvent event) { 68 | EzyLostPingEvent mevent = (EzyLostPingEvent)event; 69 | Map map = new HashMap<>(); 70 | map.put("count", mevent.getCount()); 71 | return map; 72 | } 73 | }); 74 | answer.put(EzyEventType.TRY_CONNECT, new EzyFunction() { 75 | @Override 76 | public Map apply(EzyEvent event) { 77 | EzyTryConnectEvent mevent = (EzyTryConnectEvent)event; 78 | Map map = new HashMap<>(); 79 | map.put("count", mevent.getCount()); 80 | return map; 81 | } 82 | }); 83 | return answer; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/serializer/EzyNativeDataDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.serializer; 2 | 3 | import com.tvd12.ezyfoxserver.client.entity.EzyArray; 4 | import com.tvd12.ezyfoxserver.client.entity.EzyObject; 5 | import com.tvd12.ezyfoxserver.client.factory.EzyEntityFactory; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * Created by tavandung12 on 10/25/18. 12 | */ 13 | 14 | public class EzyNativeDataDeserializer { 15 | 16 | public EzyArray fromList(List value) { 17 | EzyArray answer = EzyEntityFactory.newArray(); 18 | answer.add(value); 19 | return answer; 20 | } 21 | 22 | public EzyObject fromMap(Map value) { 23 | EzyObject answer = EzyEntityFactory.newObject(); 24 | answer.putAll(value); 25 | return answer; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/serializer/EzyNativeDataSerializer.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.serializer; 2 | 3 | import com.tvd12.ezyfoxserver.client.entity.EzyArray; 4 | import com.tvd12.ezyfoxserver.client.entity.EzyObject; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * Created by tavandung12 on 10/25/18. 11 | */ 12 | 13 | public class EzyNativeDataSerializer { 14 | 15 | public List toList(EzyArray value) { 16 | if(value == null) 17 | return null; 18 | return value.toList(); 19 | } 20 | 21 | public Map toMap(EzyObject value) { 22 | if(value == null) 23 | return null; 24 | return value.toMap(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /android/src/main/java/com/tvd12/ezyfoxserver/client/flutter/serializer/EzyNativeSerializers.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.ezyfoxserver.client.flutter.serializer; 2 | 3 | import com.tvd12.ezyfoxserver.client.config.EzyClientConfig; 4 | import com.tvd12.ezyfoxserver.client.entity.EzyArray; 5 | import com.tvd12.ezyfoxserver.client.event.EzyEvent; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * Created by tavandung12 on 10/25/18. 12 | */ 13 | 14 | public final class EzyNativeSerializers { 15 | 16 | private static final EzyEventSerializer EVENT_SERIALIZER = new EzyEventSerializer(); 17 | private static final EzyNativeDataSerializer DATA_SERIALIZER = new EzyNativeDataSerializer(); 18 | private static final EzyNativeDataDeserializer DATA_DESERIALIZER = new EzyNativeDataDeserializer(); 19 | private static final EzyClientConfigSerializer CLIENT_CONFIG_SERIALIZER = new EzyClientConfigSerializer(); 20 | 21 | private EzyNativeSerializers() { } 22 | 23 | public static Map serialize(EzyEvent event) { 24 | Map answer = EVENT_SERIALIZER.serialize(event); 25 | return answer; 26 | } 27 | 28 | public static List toList(EzyArray array) { 29 | List answer = DATA_SERIALIZER.toList(array); 30 | return answer; 31 | } 32 | 33 | public static EzyArray fromList(List array) { 34 | EzyArray answer = DATA_DESERIALIZER.fromList(array); 35 | return answer; 36 | } 37 | 38 | public static Map serialize(EzyClientConfig config) { 39 | Map answer = CLIENT_CONFIG_SERIALIZER.serialize(config); 40 | return answer; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | Podfile.lock 2 | # Miscellaneous 3 | *.class 4 | *.log 5 | *.pyc 6 | *.swp 7 | .DS_Store 8 | .atom/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Web related 36 | lib/generated_plugin_registrant.dart 37 | 38 | # Symbolication related 39 | app.*.symbols 40 | 41 | # Obfuscation related 42 | app.*.map.json 43 | 44 | # Android Studio will place build artifacts here 45 | /android/app/debug 46 | /android/app/profile 47 | /android/app/release 48 | pubspec.lock 49 | build/ 50 | */build/ 51 | target/ 52 | */target/ 53 | web/ 54 | test/ 55 | .metadata 56 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # ezyfox-server-flutter-client 2 | 3 | flutter client for [ezyfox server](https://github.com/youngmonkeys/ezyfox-server) 4 | 5 | # Architecture 6 | 7 | 8 | 9 | # Prepare 10 | 11 | 1. Download and install [JDK 8](https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html) 12 | 2. Download and install [Android Studio](https://developer.android.com/studio) 13 | 3. Download and install [Xcode](https://developer.apple.com/xcode/) 14 | 4. Download and install [Intellij and Flutter plugin](https://www.jetbrains.com/idea/download) 15 | 5. Download and instal [Flutter SDK](https://flutter.dev/docs/get-started/install) 16 | 17 | # How to test? 18 | 19 | ### 1. Clone source code 20 | 21 | ``` 22 | git@github.com:youngmonkeys/ezyfox-server-flutter-client.git 23 | ``` 24 | 25 | ### 2. Pull submodules 26 | 27 | ``` 28 | git submodule update --remote --recursive 29 | ``` 30 | 31 | ### 3. Import source code 32 | 33 | - To IntelliJ IDE: for all 34 | - To Xcode: for iOS 35 | - To Android studio: for Android 36 | 37 | ### 4. You can run 38 | 39 | - [main.dart](https://github.com/youngmonkeys/ezyfox-server-flutter-client/blob/master/lib/main.dart) on Intellij 40 | - Build and Run on Xcode for iOS, don't for get run `pod install` 41 | - Build and run on Android Studio for Android 42 | 43 | ### 5. Where need I click? 44 | 45 | - Tap to plus button in bottom right corner 46 | - When you see `Greet Flutter's developer!`, congratulation, you've just run and connect to server successfully 47 | 48 | # Contact us 49 | 50 | - Touch us on [Facebook](https://www.facebook.com/youngmonkeys.org) 51 | - Email to me [Dzung](mailto:itprono3@gmail.com) -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | gradle/ 9 | 10 | # Remember to never publicly share your keystore. 11 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 12 | key.properties 13 | **/*.keystore 14 | **/*.jks 15 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file("local.properties") 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader("UTF-8") { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterRoot = localProperties.getProperty('flutter.sdk') 16 | if (flutterRoot == null) { 17 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 18 | }// in case of error here delete keyword 'new' 19 | 20 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 21 | if (flutterVersionCode == null) { 22 | flutterVersionCode = "1" 23 | } 24 | 25 | def flutterVersionName = localProperties.getProperty("flutter.versionName") 26 | if (flutterVersionName == null) { 27 | flutterVersionName = "1.0" 28 | } 29 | 30 | android { 31 | compileSdkVersion 31 32 | 33 | compileOptions { 34 | sourceCompatibility JavaVersion.VERSION_1_8 35 | targetCompatibility JavaVersion.VERSION_1_8 36 | } 37 | 38 | defaultConfig { 39 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 40 | applicationId "com.tvd12.hello_flutter" 41 | minSdkVersion 25 42 | targetSdkVersion 33 43 | versionCode flutterVersionCode.toInteger() 44 | versionName flutterVersionName 45 | } 46 | 47 | buildTypes { 48 | release { 49 | // TODO: Add your own signing config for the release build. 50 | // Signing with the debug keys for now, so `flutter run --release` works. 51 | signingConfig signingConfigs.debug 52 | } 53 | } 54 | } 55 | 56 | flutter { 57 | source '../..' 58 | } 59 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 14 | 18 | 22 | 27 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/tvd12/hello_flutter/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.tvd12.hello_flutter; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.tvd12.ezyfoxserver.client.flutter.EzyClientProxy; 6 | 7 | import io.flutter.embedding.android.FlutterActivity; 8 | import io.flutter.embedding.engine.FlutterEngine; 9 | 10 | public class MainActivity extends FlutterActivity { 11 | 12 | @Override 13 | public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { 14 | super.configureFlutterEngine(flutterEngine); 15 | EzyClientProxy.getInstance().register( 16 | flutterEngine.getDartExecutor().getBinaryMessenger() 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = "../build" 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(":app") 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "7.3.0" apply false 22 | id "org.jetbrains.kotlin.android" version "1.7.10" apply false 23 | } 24 | 25 | include ':app' 26 | -------------------------------------------------------------------------------- /example/images/flutter-sdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/example/images/flutter-sdk.png -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /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 "Generated.xcconfig" 2 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'Runner' do 5 | # Comment the next line if you don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for Runner 9 | 10 | pod 'OpenSSL-Universal' 11 | 12 | end 13 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | let controller : FlutterViewController = window?.rootViewController as! FlutterViewController 12 | EzyClientProxy.getInstance().registration(controller.binaryMessenger) 13 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/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/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | hello_flutter 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | #import "EzyClientProxy.h" 3 | #import "EzyEncryptionProxy.h" 4 | -------------------------------------------------------------------------------- /example/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/25/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'socket_proxy.dart'; 3 | 4 | void main() { 5 | runApp(const MyApp()); 6 | } 7 | 8 | class MyApp extends StatelessWidget { 9 | const MyApp({Key? key}) : super(key: key); 10 | 11 | // This widget is the root of your application. 12 | @override 13 | Widget build(BuildContext context) { 14 | return MaterialApp( 15 | title: 'Flutter Demo', 16 | theme: ThemeData( 17 | primarySwatch: Colors.blue, 18 | ), 19 | home: const MyHomePage(title: 'Flutter Demo Home Page'), 20 | ); 21 | } 22 | } 23 | 24 | class MyHomePage extends StatefulWidget { 25 | const MyHomePage({Key? key, required this.title}) : super(key: key); 26 | 27 | final String title; 28 | 29 | @override 30 | State createState() => _MyHomePageState(); 31 | } 32 | 33 | class _MyHomePageState extends State { 34 | int _counter = 0; 35 | 36 | String socketState = 'Socket has not connected yet'; 37 | String sslMessage = ''; 38 | 39 | Future setup() async { 40 | SocketProxy socketProxy = SocketProxy.getInstance(); 41 | socketProxy.onDisconnected(() => { 42 | setState(() { 43 | socketState = 'Disconnected, retry ...'; 44 | sslMessage = ''; 45 | }) 46 | }); 47 | socketProxy.onConnectionFailed(() => { 48 | setState(() { 49 | socketState = 'Can not connect to server'; 50 | sslMessage = ''; 51 | }) 52 | }); 53 | socketProxy.onGreet((message) => { 54 | setState(() { 55 | socketState = message; 56 | sslMessage = ''; 57 | }) 58 | }); 59 | socketProxy.onSecureChat((message) => { 60 | setState(() { 61 | socketState = 'Secure Chat'; 62 | sslMessage = message; 63 | }) 64 | }); 65 | socketProxy.onConnection(() => { 66 | setState(() { 67 | socketState = 'Connected'; 68 | sslMessage = ''; 69 | }) 70 | }); 71 | } 72 | 73 | void _connect() { 74 | setState(() { 75 | _counter++; 76 | SocketProxy.getInstance().connectToServer("example", "123456"); 77 | // freechat java client default credentials 78 | }); 79 | } 80 | 81 | @override 82 | Widget build(BuildContext context) { 83 | setup(); 84 | return Scaffold( 85 | appBar: AppBar( 86 | title: Text(widget.title), 87 | ), 88 | body: Center( 89 | child: Column( 90 | mainAxisAlignment: MainAxisAlignment.center, 91 | children: [ 92 | const Text( 93 | 'You have pushed the button this many times:', 94 | ), 95 | Text( 96 | '$_counter', 97 | style: Theme.of(context).textTheme.headlineMedium, 98 | ), 99 | const Text( 100 | 'Socket message: ', 101 | ), 102 | Text( 103 | '$socketState', 104 | style: Theme.of(context).textTheme.headlineMedium, 105 | ), 106 | const Text( 107 | 'SSL message: ', 108 | ), 109 | Text( 110 | '$sslMessage', 111 | style: Theme.of(context).textTheme.headlineMedium, 112 | ) 113 | ], 114 | ), 115 | ), 116 | floatingActionButton: FloatingActionButton( 117 | onPressed: _connect, 118 | tooltip: 'Connect', 119 | child: const Icon(Icons.add), 120 | ), // This trailing comma makes auto-formatting nicer for build methods. 121 | ); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /example/lib/socket_proxy.dart: -------------------------------------------------------------------------------- 1 | import 'package:ezyfox_server_flutter_client/ezy_client.dart'; 2 | import 'package:ezyfox_server_flutter_client/ezy_clients.dart'; 3 | import 'package:ezyfox_server_flutter_client/ezy_config.dart'; 4 | import 'package:ezyfox_server_flutter_client/ezy_constants.dart'; 5 | import 'package:ezyfox_server_flutter_client/ezy_entities.dart'; 6 | import 'package:ezyfox_server_flutter_client/ezy_handlers.dart'; 7 | 8 | const ZONE_NAME = "freechat"; 9 | const APP_NAME = "freechat"; 10 | 11 | class SocketProxy { 12 | bool settedUp = false; 13 | late String username; 14 | late String password; 15 | late EzyClient _client; 16 | late Function(String)? _greetCallback; 17 | late Function(String)? _secureChatCallback; 18 | late Function? _disconnectedCallback; 19 | late Function? _connectionCallback; 20 | late Function? _connectionFailedCallback; 21 | static final SocketProxy _INSTANCE = SocketProxy._(); 22 | 23 | SocketProxy._() {} 24 | 25 | static SocketProxy getInstance() { 26 | return _INSTANCE; 27 | } 28 | 29 | void _setup() { 30 | EzyConfig config = EzyConfig(); 31 | config.clientName = ZONE_NAME; 32 | config.enableSSL = 33 | false; // SSL is not active by default using freechat server 34 | config.ping.maxLostPingCount = 3; 35 | config.ping.pingPeriod = 1000; 36 | config.reconnect.maxReconnectCount = 10; 37 | config.reconnect.reconnectPeriod = 1000; 38 | // config.enableDebug = true; 39 | EzyClients clients = EzyClients.getInstance(); 40 | _client = clients.newDefaultClient(config); 41 | _client.setup.addEventHandler(EzyEventType.DISCONNECTION, 42 | _DisconnectionHandler(_disconnectedCallback!)); 43 | _client.setup.addEventHandler(EzyEventType.CONNECTION_SUCCESS, 44 | _connectionHandler(_connectionCallback!)); 45 | _client.setup.addEventHandler(EzyEventType.CONNECTION_FAILURE, 46 | _ConnectionFailureHandler(_connectionFailedCallback!)); 47 | _client.setup.addDataHandler(EzyCommand.HANDSHAKE, _HandshakeHandler()); 48 | _client.setup.addDataHandler(EzyCommand.LOGIN, _LoginSuccessHandler()); 49 | _client.setup.addDataHandler(EzyCommand.APP_ACCESS, _AppAccessHandler()); 50 | var appSetup = _client.setup.setupApp(APP_NAME); 51 | appSetup.addDataHandler("greet", _GreetResponseHandler((message) { 52 | _greetCallback!(message); 53 | })); 54 | appSetup.addDataHandler("secureChat", _SecureChatResponseHandler((message) { 55 | _secureChatCallback!(message); 56 | })); 57 | } 58 | 59 | void connectToServer(String username, String password) { 60 | if (!settedUp) { 61 | settedUp = true; 62 | _setup(); 63 | } 64 | this.username = username; 65 | this.password = password; 66 | // this._client.connect("127.0.0.1", 3005); 67 | this._client.connect("10.0.2.2", 3005); 68 | // this._client.connect("tvd12.com", 3005); 69 | } 70 | 71 | void onGreet(Function(String) callback) { 72 | _greetCallback = callback; 73 | } 74 | 75 | void onSecureChat(Function(String) callback) { 76 | _secureChatCallback = callback; 77 | } 78 | 79 | void onDisconnected(Function callback) { 80 | _disconnectedCallback = callback; 81 | } 82 | 83 | void onConnection(Function callback) { 84 | _connectionCallback = callback; 85 | } 86 | 87 | void onConnectionFailed(Function callback) { 88 | _connectionFailedCallback = callback; 89 | } 90 | } 91 | 92 | class _HandshakeHandler extends EzyHandshakeHandler { 93 | @override 94 | List getLoginRequest() { 95 | var request = []; 96 | request.add(ZONE_NAME); 97 | request.add(SocketProxy.getInstance().username); 98 | request.add(SocketProxy.getInstance().password); 99 | request.add([]); 100 | return request; 101 | } 102 | } 103 | 104 | class _LoginSuccessHandler extends EzyLoginSuccessHandler { 105 | @override 106 | void handleLoginSuccess(responseData) { 107 | client.send(EzyCommand.APP_ACCESS, [APP_NAME]); 108 | } 109 | } 110 | 111 | class _AppAccessHandler extends EzyAppAccessHandler { 112 | @override 113 | void postHandle(EzyApp app, List data) { 114 | app.send("greet", {"who": "Flutter's developer"}); 115 | } 116 | } 117 | 118 | class _GreetResponseHandler extends EzyAppDataHandler { 119 | late Function(String) _callback; 120 | 121 | _GreetResponseHandler(Function(String) callback) { 122 | _callback = callback; 123 | } 124 | 125 | @override 126 | void handle(EzyApp app, Map data) { 127 | _callback(data["message"]); 128 | app.send("secureChat", {"who": "Young Monkey"}, true); 129 | } 130 | } 131 | 132 | class _SecureChatResponseHandler extends EzyAppDataHandler { 133 | late Function(String) _callback; 134 | 135 | _SecureChatResponseHandler(Function(String) callback) { 136 | _callback = callback; 137 | } 138 | 139 | @override 140 | void handle(EzyApp app, Map data) { 141 | _callback(data["secure-message"]); 142 | } 143 | } 144 | 145 | class _DisconnectionHandler extends EzyDisconnectionHandler { 146 | late Function _callback; 147 | 148 | _DisconnectionHandler(Function callback) { 149 | _callback = callback; 150 | } 151 | @override 152 | void postHandle(Map event) { 153 | _callback(); 154 | } 155 | } 156 | 157 | class _ConnectionFailureHandler extends EzyConnectionFailureHandler { 158 | late Function _callback; 159 | 160 | _ConnectionFailureHandler(Function callback) { 161 | _callback = callback; 162 | } 163 | 164 | @override 165 | void onConnectionFailed(Map event) { 166 | _callback(); 167 | } 168 | } 169 | 170 | class _connectionHandler extends EzyConnectionSuccessHandler { 171 | late Function _callback; 172 | 173 | _connectionHandler(Function callback) { 174 | _callback = callback; 175 | } 176 | 177 | @override 178 | void handle(Map event) { 179 | sendHandshakeRequest(); 180 | postHandle(); 181 | _callback(); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: hello_flutter 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | # Dependencies specify other packages that your package needs in order to work. 24 | # To automatically upgrade your package dependencies to the latest versions 25 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 26 | # dependencies can be manually updated by changing the version numbers below to 27 | # the latest version available on pub.dev. To see which dependencies have newer 28 | # versions available, run `flutter pub outdated`. 29 | dependencies: 30 | flutter: 31 | sdk: flutter 32 | ezyfox_server_flutter_client: 33 | path: ./../ 34 | 35 | 36 | # The following adds the Cupertino Icons font to your application. 37 | # Use with the CupertinoIcons class for iOS style icons. 38 | cupertino_icons: ^1.0.8 39 | material_color_utilities: ^0.8.0 40 | 41 | dev_dependencies: 42 | flutter_test: 43 | sdk: flutter 44 | 45 | # The "flutter_lints" package below contains a set of recommended lints to 46 | # encourage good coding practices. The lint set provided by the package is 47 | # activated in the `analysis_options.yaml` file located at the root of your 48 | # package. See that file for information about deactivating specific lint 49 | # rules and activating additional ones. 50 | flutter_lints: ^4.0.0 51 | 52 | # For information on the generic Dart part of this file, see the 53 | # following page: https://dart.dev/tools/pub/pubspec 54 | 55 | # The following section is specific to Flutter. 56 | flutter: 57 | 58 | # The following line ensures that the Material Icons font is 59 | # included with your application, so that you can use the icons in 60 | # the material Icons class. 61 | uses-material-design: true 62 | 63 | # To add assets to your application, add an assets section, like this: 64 | # assets: 65 | # - images/a_dot_burr.jpeg 66 | # - images/a_dot_ham.jpeg 67 | 68 | # An image asset can refer to one or more resolution-specific "variants", see 69 | # https://flutter.dev/assets-and-images/#resolution-aware. 70 | 71 | # For details regarding adding assets from package dependencies, see 72 | # https://flutter.dev/assets-and-images/#from-packages 73 | 74 | # To add custom fonts to your application, add a fonts section here, 75 | # in this "flutter" section. Each entry in this list should have a 76 | # "family" key with the font family name, and a "fonts" key with a 77 | # list giving the asset and other descriptors for the font. For 78 | # example: 79 | # fonts: 80 | # - family: Schyler 81 | # fonts: 82 | # - asset: fonts/Schyler-Regular.ttf 83 | # - asset: fonts/Schyler-Italic.ttf 84 | # style: italic 85 | # - family: Trajan Pro 86 | # fonts: 87 | # - asset: fonts/TrajanPro.ttf 88 | # - asset: fonts/TrajanPro_Bold.ttf 89 | # weight: 700 90 | # 91 | # For details regarding fonts from package dependencies, 92 | # see https://flutter.dev/custom-fonts/#from-packages 93 | -------------------------------------------------------------------------------- /images/flutter-sdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/images/flutter-sdk.png -------------------------------------------------------------------------------- /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 | /Flutter/ephemeral/ 38 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngmonkeys/ezyfox-server-flutter-client/eb1dd0e6692afb1ab081bb88cbbfd6cb0099d059/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/EzyClient/EzyClientProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyClientProxy.h 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/26/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class EzyMethodProxy; 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | @interface EzyClientProxy : NSObject 17 | +(instancetype)getInstance; 18 | -(void)registration:(NSObject*)messager; 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /ios/EzyClient/EzyClientProxy.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyClientProxy.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/26/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #include "EzyHeaders.h" 10 | #import "EzyClientProxy.h" 11 | #import "proxy/EzyMethodProxy.h" 12 | #import "exception/EzyMethodCallException.h" 13 | 14 | EZY_USING_NAMESPACE; 15 | 16 | std::vector clientVector; 17 | 18 | @implementation EzyClientProxy { 19 | BOOL _registed; 20 | FlutterMethodChannel* _methodChannel; 21 | NSDictionary* _methods; 22 | } 23 | 24 | + (instancetype)getInstance { 25 | static EzyClientProxy *sInstance = nil; 26 | static dispatch_once_t onceToken; 27 | dispatch_once(&onceToken, ^{ 28 | sInstance = [[EzyClientProxy alloc] init]; 29 | }); 30 | return sInstance; 31 | } 32 | 33 | -(instancetype)init { 34 | self = [super init]; 35 | if(self) { 36 | _registed = false; 37 | _methods = [NSMutableDictionary dictionary]; 38 | } 39 | return self; 40 | } 41 | 42 | -(void)registration:(NSObject*)messager { 43 | if (_registed) { 44 | return; 45 | } 46 | _registed = true; 47 | _methodChannel = [FlutterMethodChannel 48 | methodChannelWithName:@"com.tvd12.ezyfoxserver.client" 49 | binaryMessenger:messager]; 50 | [_methodChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { 51 | [EzyClientProxy.getInstance run:call.method params:call.arguments callback:result]; 52 | }]; 53 | [self addDefaultMethods]; 54 | 55 | NSThread* thread = [[NSThread alloc] initWithTarget:self 56 | selector:@selector(loopProcessEvents) 57 | object:nil]; 58 | [thread start]; 59 | } 60 | 61 | -(void)run:(NSString*)method params:(NSDictionary*)params callback:(FlutterResult)callback { 62 | EzyMethodProxy* func = [_methods valueForKey:method]; 63 | if(!func) { 64 | NSString* exceptionReason = [NSString stringWithFormat:@"has no method: %@", method]; 65 | @throw [NSException exceptionWithName:@"NSInvalidArgumentException" reason:exceptionReason userInfo:nil]; 66 | } 67 | @try { 68 | [func validate:params]; 69 | NSObject* result = [func invoke:params]; 70 | callback(result); 71 | } 72 | @catch (EzyMethodCallException* e) { 73 | NSLog(@"call method: %@ with params %@ error: %@", method, params, [e reason]); 74 | if(callback) { 75 | callback([FlutterError errorWithCode: [e code] 76 | message: [e reason] 77 | details: [e description]]); 78 | } 79 | } 80 | @catch (NSException* e) { 81 | NSLog(@"call method: %@ with params %@ fatal error: %@", method, params, [e reason]); 82 | } 83 | } 84 | 85 | - (void) loopProcessEvents { 86 | EzyClients* clients = EzyClients::getInstance(); 87 | while (true) { 88 | [[NSThread currentThread] setName:@"ezyfox-process-event"]; 89 | dispatch_sync(dispatch_get_main_queue(), ^(void) { 90 | clients->getClients(clientVector); 91 | for(int i = 0 ; i < clientVector.size() ; ++i) { 92 | EzyClient* client = clientVector[i]; 93 | client->processEvents(); 94 | } 95 | }); 96 | [NSThread sleepForTimeInterval:0.003]; 97 | } 98 | } 99 | 100 | -(void)addDefaultMethods { 101 | [self addMethod:[[EzyCreateClientMethod alloc]initWithComponents:_methodChannel]]; 102 | [self addMethod:[[EzyConnectMethod alloc]init]]; 103 | [self addMethod:[[EzyReconnectMethod alloc]init]]; 104 | [self addMethod:[[EzyDisconnectMethod alloc]init]]; 105 | [self addMethod:[[EzySendMethod alloc]init]]; 106 | [self addMethod:[[EzySetStatusMethod alloc]init]]; 107 | [self addMethod:[[EzyStartPingScheduleMethod alloc]init]]; 108 | [self addMethod:[[EzyGenerateKeyPairMethod alloc]init]]; 109 | [self addMethod:[[EzyRsaDecryptMethod alloc]init]]; 110 | [self addMethod:[[EzyLogMethod alloc]init]]; 111 | [self addMethod:[[EzySetSessionKeyMethod alloc]init]]; 112 | } 113 | 114 | -(void)addMethod:(EzyMethodProxy*)method { 115 | [_methods setValue:method forKey:[method getName]]; 116 | } 117 | 118 | @end 119 | -------------------------------------------------------------------------------- /ios/EzyClient/EzyFlutterClientPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface EzyFlutterClientPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /ios/EzyClient/EzyFlutterClientPlugin.m: -------------------------------------------------------------------------------- 1 | #import "EzyFlutterClientPlugin.h" 2 | #import "EzyClientProxy.h" 3 | 4 | @implementation EzyFlutterClientPlugin 5 | + (void)registerWithRegistrar:(NSObject*)registrar { 6 | [[EzyClientProxy getInstance] registration: [registrar messenger]]; 7 | } 8 | @end 9 | -------------------------------------------------------------------------------- /ios/EzyClient/EzyMethodNames.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyMethodNames.h 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/26/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | FOUNDATION_EXPORT NSString *const METHOD_INIT; 10 | FOUNDATION_EXPORT NSString *const METHOD_CONNECT; 11 | FOUNDATION_EXPORT NSString *const METHOD_DISCONNECT; 12 | FOUNDATION_EXPORT NSString *const METHOD_SEND; 13 | FOUNDATION_EXPORT NSString *const METHOD_RECONNECT; 14 | FOUNDATION_EXPORT NSString *const METHOD_SET_STATUS; 15 | FOUNDATION_EXPORT NSString *const METHOD_START_PING_SCHEDULE; 16 | FOUNDATION_EXPORT NSString *const METHOD_GENERATE_KEY_PAIR; 17 | FOUNDATION_EXPORT NSString *const METHOD_RSA_DECRYPT; 18 | FOUNDATION_EXPORT NSString *const METHOD_LOG; 19 | FOUNDATION_EXPORT NSString *const METHOD_SET_SESSION_KEY; 20 | -------------------------------------------------------------------------------- /ios/EzyClient/EzyMethodNames.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyMethodNames.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EzyMethodNames.h" 11 | 12 | NSString *const METHOD_INIT = @"init"; 13 | NSString *const METHOD_CONNECT = @"connect"; 14 | NSString *const METHOD_DISCONNECT = @"disconnect"; 15 | NSString *const METHOD_SEND = @"send"; 16 | NSString *const METHOD_RECONNECT = @"reconnect"; 17 | NSString *const METHOD_SET_STATUS = @"setStatus"; 18 | NSString *const METHOD_START_PING_SCHEDULE = @"startPingSchedule"; 19 | NSString *const METHOD_GENERATE_KEY_PAIR = @"generateKeyPair"; 20 | NSString *const METHOD_RSA_DECRYPT = @"rsaDecrypt"; 21 | NSString *const METHOD_LOG = @"log"; 22 | NSString *const METHOD_SET_SESSION_KEY = @"setSessionKey"; 23 | -------------------------------------------------------------------------------- /ios/EzyClient/Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'iphone' target in the 'iphone' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | 10 | #ifdef __cplusplus 11 | #include "EzyHeaders.h" 12 | #endif 13 | -------------------------------------------------------------------------------- /ios/EzyClient/codec/EzyEncryptionProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyEncryptionProxy.h 3 | // ezyfox-ssl 4 | // 5 | // Created by Dzung on 31/05/2021. 6 | // 7 | 8 | #import 9 | #import "../util/NSByteArray.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface EzyKeyPairProxy : NSObject 14 | 15 | @property NSString *publicKey; 16 | @property NSString *privateKey; 17 | 18 | +(id)keyPairWith: (NSString*)publicKey privateKey:(NSString*)privateKey; 19 | @end 20 | 21 | @interface EzyRSAProxy : NSObject 22 | +(instancetype)getInstance; 23 | -(EzyKeyPairProxy*)generateKeyPair; 24 | -(NSData*)decrypt: (NSData*)message privateKey:(NSData*)privateKey; 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /ios/EzyClient/codec/EzyEncryptionProxy.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyEncryptionProxy.mm 3 | // ezyfox-ssl 4 | // 5 | // Created by Dzung on 31/05/2021. 6 | // 7 | 8 | #include "EzyHeaders.h" 9 | #import "EzyEncryptionProxy.h" 10 | 11 | EZY_USING_NAMESPACE; 12 | EZY_USING_NAMESPACE::codec; 13 | 14 | @implementation EzyKeyPairProxy { 15 | } 16 | +(id)keyPairWith:(NSString *)publicKey privateKey:(NSString *)privateKey { 17 | EzyKeyPairProxy* pRet = [[EzyKeyPairProxy alloc] init]; 18 | pRet.publicKey = publicKey; 19 | pRet.privateKey = privateKey; 20 | return pRet; 21 | } 22 | @end 23 | 24 | @implementation EzyRSAProxy { 25 | } 26 | 27 | + (instancetype)getInstance { 28 | static EzyRSAProxy *sInstance = nil; 29 | static dispatch_once_t onceToken; 30 | dispatch_once(&onceToken, ^{ 31 | sInstance = [[EzyRSAProxy alloc] init]; 32 | }); 33 | return sInstance; 34 | } 35 | 36 | -(EzyKeyPairProxy*)generateKeyPair { 37 | EzyKeyPair* keyPair = EzyRSA::getInstance()->generateKeyPair(); 38 | return [EzyKeyPairProxy 39 | keyPairWith:[NSString stringWithCString:keyPair->getPublicKey().c_str() 40 | encoding: [NSString defaultCStringEncoding]] 41 | privateKey:[NSString stringWithCString:keyPair->getPrivateKey().c_str() 42 | encoding: [NSString defaultCStringEncoding]]]; 43 | } 44 | 45 | -(NSData*)decrypt:(NSData *)message privateKey:(NSData *)privateKey { 46 | int decryptedSize = 0; 47 | char* decryption = EzyRSA::getInstance()->decrypt((char*)[message bytes], 48 | (int)message.length, 49 | (char*)[privateKey bytes], 50 | decryptedSize); 51 | NSData* answer = [NSData dataWithBytes:decryption length:decryptedSize]; 52 | EZY_SAFE_FREE(decryption); 53 | return answer; 54 | } 55 | @end 56 | -------------------------------------------------------------------------------- /ios/EzyClient/exception/EzyMethodCallException.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyMethodCallException.h 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | FOUNDATION_EXPORT NSExceptionName MethodCallException; 14 | 15 | @interface EzyMethodCallException : NSException 16 | @property (strong, nonatomic) NSString* code; 17 | -(void)setCode:(NSString*)code; 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /ios/EzyClient/exception/EzyMethodCallException.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyMethodCallException.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import "EzyMethodCallException.h" 10 | 11 | @implementation EzyMethodCallException 12 | - (void)setCode:(NSString *)code { 13 | _code = code; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /ios/EzyClient/math/EzyNSNumber.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyNSNumber.h 3 | // freechat-swift 4 | // 5 | // Created by Dung Ta Van on 1/18/20. 6 | // Copyright © 2020 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(int, NumberType) { 14 | NUMBER_TYPE_BOOL = 1, 15 | NUMBER_TYPE_DOUBLE = 2, 16 | NUMBER_TYPE_FLOAT = 3, 17 | NUMBER_TYPE_INT = 4, 18 | NUMBER_TYPE_UINT = 5 19 | }; 20 | 21 | @interface EzyNSNumber : NSObject 22 | 23 | @property (assign) int mType; 24 | @property (nonatomic, strong) NSNumber* mNumber; 25 | 26 | -(id) initWithBool:(bool)value; 27 | -(id) initWithDouble:(double)value; 28 | -(id) initWithFloat:(float)value; 29 | -(id) initWithInt:(int64_t)value; 30 | -(id) initWithUInt:(uint64_t)value; 31 | 32 | -(int) getType; 33 | -(bool) boolValue; 34 | -(double) doubleValue; 35 | -(float) floatValue; 36 | -(int64_t) intValue; 37 | -(uint64_t) uintValue; 38 | 39 | +(instancetype) numberWithBool:(bool)value; 40 | +(instancetype) numberWithDouble:(double)value; 41 | +(instancetype) numberWithFloat:(float)value; 42 | +(instancetype) numberWithInt:(int64_t)value; 43 | +(instancetype) numberWithUInt:(uint64_t)value; 44 | 45 | @end 46 | 47 | NS_ASSUME_NONNULL_END 48 | -------------------------------------------------------------------------------- /ios/EzyClient/math/EzyNSNumber.m: -------------------------------------------------------------------------------- 1 | // 2 | // EzyNSNumber.m 3 | // freechat-swift 4 | // 5 | // Created by Dung Ta Van on 1/18/20. 6 | // Copyright © 2020 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import "EzyNSNumber.h" 10 | 11 | @implementation EzyNSNumber 12 | 13 | + (instancetype)numberWithBool:(bool)value { 14 | return [[EzyNSNumber alloc] initWithBool:value]; 15 | } 16 | 17 | + (instancetype)numberWithDouble:(double)value { 18 | return [[EzyNSNumber alloc] initWithDouble:value]; 19 | } 20 | 21 | + (instancetype)numberWithFloat:(float)value { 22 | return [[EzyNSNumber alloc] initWithFloat:value]; 23 | } 24 | 25 | + (instancetype)numberWithInt:(int64_t)value { 26 | return [[EzyNSNumber alloc] initWithInt:value]; 27 | } 28 | 29 | + (instancetype)numberWithUInt:(uint64_t)value { 30 | return [[EzyNSNumber alloc] initWithUInt:value]; 31 | } 32 | 33 | - (id)initWithBool:(bool)value { 34 | self = [super init]; 35 | if(self) { 36 | self.mType = NUMBER_TYPE_BOOL; 37 | self.mNumber = [NSNumber numberWithBool:value]; 38 | } 39 | return self; 40 | } 41 | 42 | - (id)initWithDouble:(double)value { 43 | self = [super init]; 44 | if(self) { 45 | self.mType = NUMBER_TYPE_DOUBLE; 46 | self.mNumber = [NSNumber numberWithDouble:value]; 47 | } 48 | return self; 49 | } 50 | 51 | - (id)initWithFloat:(float)value { 52 | self = [super init]; 53 | if(self) { 54 | self.mType = NUMBER_TYPE_FLOAT; 55 | self.mNumber = [NSNumber numberWithFloat:value]; 56 | } 57 | return self; 58 | } 59 | 60 | - (id)initWithInt:(int64_t)value { 61 | self = [super init]; 62 | if(self) { 63 | self.mType = NUMBER_TYPE_INT; 64 | self.mNumber = [NSNumber numberWithLongLong:value]; 65 | } 66 | return self; 67 | } 68 | 69 | - (id)initWithUInt:(uint64_t)value { 70 | self = [super init]; 71 | if(self) { 72 | self.mType = NUMBER_TYPE_UINT; 73 | self.mNumber = [NSNumber numberWithUnsignedLongLong:value]; 74 | } 75 | return self; 76 | } 77 | 78 | - (int)getType { 79 | return self.mType; 80 | } 81 | 82 | - (bool)boolValue { 83 | return [[self mNumber] boolValue]; 84 | } 85 | 86 | - (double)doubleValue { 87 | return [[self mNumber] doubleValue]; 88 | } 89 | 90 | - (float)floatValue { 91 | return [[self mNumber] floatValue]; 92 | } 93 | 94 | - (int64_t)intValue { 95 | return [[self mNumber] longLongValue]; 96 | } 97 | 98 | - (uint64_t)uintValue { 99 | return [[self mNumber] unsignedLongLongValue]; 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /ios/EzyClient/proxy/EzyMethodProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyMethodProxy.h 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/26/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface EzyMethodProxy : NSObject 15 | -(void)validate: (NSDictionary*)params; 16 | -(NSObject*)invoke: (NSDictionary*)params; 17 | -(NSString*)getName; 18 | @end 19 | 20 | @interface EzyCreateClientMethod : EzyMethodProxy 21 | -(instancetype)initWithComponents:(FlutterMethodChannel*)methodChannel; 22 | @end 23 | 24 | @interface EzyConnectMethod : EzyMethodProxy 25 | @end 26 | 27 | @interface EzyReconnectMethod : EzyMethodProxy 28 | @end 29 | 30 | @interface EzyDisconnectMethod : EzyMethodProxy 31 | @end 32 | 33 | @interface EzySendMethod : EzyMethodProxy 34 | @end 35 | 36 | @interface EzySetStatusMethod : EzyMethodProxy 37 | @end 38 | 39 | @interface EzyStartPingScheduleMethod : EzyMethodProxy 40 | @end 41 | 42 | @interface EzyGenerateKeyPairMethod : EzyMethodProxy 43 | @end 44 | 45 | @interface EzyRsaDecryptMethod : EzyMethodProxy 46 | @end 47 | 48 | @interface EzyLogMethod : EzyMethodProxy 49 | @end 50 | 51 | @interface EzySetSessionKeyMethod : EzyMethodProxy 52 | @end 53 | 54 | NS_ASSUME_NONNULL_END 55 | -------------------------------------------------------------------------------- /ios/EzyClient/proxy/EzyMethodProxy.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyMethodProxy.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/26/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include "EzyHeaders.h" 12 | #import "EzyMethodProxy.h" 13 | #import "../EzyMethodNames.h" 14 | #import "../util/NSByteArray.h" 15 | #import "../util/EzyNativeStrings.h" 16 | #import "../serializer/EzyNativeSerializers.h" 17 | #import "../codec/EzyEncryptionProxy.h" 18 | 19 | EZY_USING_NAMESPACE; 20 | EZY_USING_NAMESPACE::config; 21 | EZY_USING_NAMESPACE::setup; 22 | EZY_USING_NAMESPACE::constant; 23 | EZY_USING_NAMESPACE::event; 24 | EZY_USING_NAMESPACE::handler; 25 | EZY_USING_NAMESPACE::entity; 26 | EZY_USING_NAMESPACE::socket; 27 | EZY_USING_NAMESPACE::codec; 28 | 29 | static std::map sNativeEventTypeNames = { 30 | {ConnectionSuccess, "CONNECTION_SUCCESS"}, 31 | {ConnectionFailure, "CONNECTION_FAILURE"}, 32 | {Disconnection, "DISCONNECTION"}, 33 | {LostPing, "LOST_PING"}, 34 | {TryConnect, "TRY_CONNECT"} 35 | }; 36 | 37 | static std::map sNativeCommandNames = { 38 | {Error, "ERROR"}, 39 | {Handshake, "HANDSHAKE"}, 40 | {Ping, "PING"}, 41 | {Pong, "PONG"}, 42 | {Disconnect, "DISCONNECT"}, 43 | {Login, "LOGIN"}, 44 | {LoginError, "LOGIN_ERROR"}, 45 | {AppAccess, "APP_ACCESS"}, 46 | {AppRequest, "APP_REQUEST"}, 47 | {AppExit, "APP_EXIT"}, 48 | {AppAccessError, "APP_ACCESS_ERROR"}, 49 | {AppRequestError, "APP_REQUEST_ERROR"}, 50 | {PluginInfo, "PLUGIN_INFO"}, 51 | {PluginRequest, "PLUGIN_REQUEST"} 52 | }; 53 | 54 | static std::map sNativeCommandIds = { 55 | {"ERROR", Error}, 56 | {"HANDSHAKE", Handshake}, 57 | {"PING", Ping}, 58 | {"PONG", Pong}, 59 | {"DISCONNECT", Disconnect}, 60 | {"LOGIN", Login}, 61 | {"LOGIN_ERROR", LoginError}, 62 | {"APP_ACCESS", AppAccess}, 63 | {"APP_REQUEST", AppRequest}, 64 | {"APP_EXIT", AppExit}, 65 | {"APP_ACCESS_ERROR", AppAccessError}, 66 | {"PLUGIN_INFO", PluginInfo}, 67 | {"PLUGIN_REQUEST", PluginRequest} 68 | }; 69 | 70 | static std::map sNativeConnectionStatusIds = { 71 | {"NULL", Null}, 72 | {"CONNECTING", Connecting}, 73 | {"CONNECTED", Connected}, 74 | {"DISCONNECTED", Disconnected}, 75 | {"FAILURE", Failure}, 76 | {"RECONNECTING", Reconnecting} 77 | }; 78 | 79 | //====================================================== 80 | 81 | EzyClients* clients = EzyClients::getInstance(); 82 | 83 | EzyClient* getClient(std::string name) { 84 | EzyClient* client = clients->getClient(name); 85 | return client; 86 | } 87 | 88 | EzyClient* getClient(NSString* name) { 89 | EzyClient* client = getClient([name UTF8String]); 90 | return client; 91 | } 92 | 93 | EzyClient* getClient(NSDictionary* params) { 94 | NSString* clientName = [params valueForKey:@"clientName"]; 95 | if(!clientName) 96 | [NSException raise:NSInvalidArgumentException format:@"must specific client name"]; 97 | EzyClient* client = getClient(clientName); 98 | return client; 99 | } 100 | 101 | EzyClientConfig* newConfig(NSDictionary* params) { 102 | EzyClientConfig* config = EzyClientConfig::create(); 103 | NSString* clientName = [params valueForKey:@"clientName"]; 104 | NSString* zoneName = [params valueForKey:@"zoneName"]; 105 | NSDictionary* ping = [params valueForKey:@"ping"]; 106 | NSDictionary* reconnect = [params valueForKey:@"reconnect"]; 107 | if(clientName) 108 | config->setClientName([clientName UTF8String]); 109 | if(zoneName) 110 | config->setZoneName([zoneName UTF8String]); 111 | if(ping) { 112 | NSNumber* pingPeriod = [ping objectForKey:@"pingPeriod"]; 113 | NSNumber* maxLostPingCount = [ping objectForKey:@"maxLostPingCount"]; 114 | EzyPingConfig* pingConfig = config->getPing(); 115 | if(pingPeriod) { 116 | pingConfig->setPingPeriod((int)[pingPeriod integerValue]); 117 | } 118 | if(maxLostPingCount) { 119 | pingConfig->setMaxLostPingCount((int)[maxLostPingCount integerValue]); 120 | } 121 | } 122 | if(reconnect) { 123 | NSNumber* enable = [reconnect objectForKey:@"enable"]; 124 | NSNumber* reconnectPeriod = [reconnect objectForKey:@"reconnectPeriod"]; 125 | NSNumber* maxReconnectCount = [reconnect objectForKey:@"maxReconnectCount"]; 126 | EzyReconnectConfig* reconnectConfig = config->getReconnect(); 127 | if(enable) 128 | reconnectConfig->setEnable([enable boolValue]); 129 | if(reconnectConfig) 130 | reconnectConfig->setReconnectPeriod((int)[reconnectPeriod integerValue]); 131 | if(maxReconnectCount) 132 | reconnectConfig->setMaxReconnectCount((int)[maxReconnectCount integerValue]); 133 | } 134 | return config; 135 | } 136 | 137 | //====================================================== 138 | 139 | class EzyNativeEventHandler : public EzyEventHandler { 140 | private: 141 | EzyClient* mClient; 142 | FlutterMethodChannel* mMethodChannel; 143 | public: 144 | EzyNativeEventHandler(EzyClient* client, FlutterMethodChannel* methodChannel) { 145 | this->mClient = client; 146 | this->mMethodChannel = methodChannel; 147 | } 148 | ~EzyNativeEventHandler() { 149 | this->mClient = 0; 150 | this->mMethodChannel = 0; 151 | } 152 | public: 153 | void handle(EzyEvent* event) { 154 | std::string eventTypeName = sNativeEventTypeNames[event->getType()]; 155 | NSDictionary* params = [NSMutableDictionary dictionary]; 156 | NSDictionary* eventData = [EzyNativeSerializers serializeEvent:event]; 157 | [params setValue:[EzyNativeStrings newNSString:mClient->getName().c_str()] forKey:@"clientName"]; 158 | [params setValue:[EzyNativeStrings newNSString:eventTypeName.c_str()] forKey:@"eventType"]; 159 | [params setValue:eventData forKey:@"data"]; 160 | [mMethodChannel invokeMethod:@"ezy.event" arguments:params]; 161 | } 162 | }; 163 | 164 | class EzyNativeDataHandler : public EzyDataHandler { 165 | private: 166 | EzyClient* mClient; 167 | FlutterMethodChannel* mMethodChannel; 168 | EzyCommand mCommand; 169 | public: 170 | EzyNativeDataHandler(EzyClient* client, 171 | FlutterMethodChannel* mMethodChannel, 172 | EzyCommand command) { 173 | this->mClient = client; 174 | this->mMethodChannel = mMethodChannel; 175 | this->mCommand = command; 176 | } 177 | ~EzyNativeDataHandler() { 178 | this->mClient = 0; 179 | this->mMethodChannel = 0; 180 | } 181 | public: 182 | void handle(entity::EzyArray* data) { 183 | std::string commandName = sNativeCommandNames[mCommand]; 184 | NSDictionary* params = [NSMutableDictionary dictionary]; 185 | NSArray* commandData = [EzyNativeSerializers toWritableArray:data]; 186 | [params setValue:[EzyNativeStrings newNSString:mClient->getName().c_str()] forKey:@"clientName"]; 187 | [params setValue:[EzyNativeStrings newNSString:commandName.c_str()] forKey:@"command"]; 188 | [params setValue:commandData forKey:@"data"]; 189 | [mMethodChannel invokeMethod:@"ezy.data" arguments:params]; 190 | } 191 | }; 192 | 193 | //====================================================== 194 | 195 | @implementation EzyMethodProxy 196 | -(void)validate:(NSDictionary *)params {} 197 | -(NSObject*)invoke: (NSDictionary*) params {return nil;} 198 | -(NSString*)getName {return nil;} 199 | @end 200 | 201 | //====================================================== 202 | @implementation EzyCreateClientMethod 203 | FlutterMethodChannel* mMethodChannel; 204 | 205 | - (instancetype)initWithComponents:(FlutterMethodChannel*)methodChannel { 206 | self = [super init]; 207 | if(self) { 208 | mMethodChannel = methodChannel; 209 | } 210 | return self; 211 | } 212 | 213 | -(void)validate:(NSDictionary *)params { 214 | if(!params) 215 | [NSException raise:NSInvalidArgumentException format:@"the config is null, can't create an client"]; 216 | if(![params objectForKey: @"zoneName"]) 217 | [NSException raise:NSInvalidArgumentException format:@"must specific zone name"]; 218 | } 219 | 220 | -(NSObject*)invoke:(NSDictionary *)params { 221 | EzyClientConfig* config = newConfig(params); 222 | EzyClient* client = getClient(config->getClientName()); 223 | if(!client) { 224 | client = clients->newClient(config); 225 | [self setupClient:client]; 226 | } 227 | NSDictionary* configMap = [EzyNativeSerializers serializeClientConfig:config]; 228 | return configMap; 229 | } 230 | 231 | -(void) setupClient:(EzyClient*)client { 232 | EzySetup* setup = client->setup(); 233 | for(int i = 1 ; i <= NUMBER_OF_EVENTS ; ++i) { 234 | EzyEventType eventType = (EzyEventType)i; 235 | setup->addEventHandler(eventType, new EzyNativeEventHandler(client, mMethodChannel)); 236 | } 237 | for(int i = 0 ; i < NUMBER_OF_COMMANDS ; ++i) { 238 | EzyCommand command = (EzyCommand)sCommands[i]; 239 | setup->addDataHandler(command, new EzyNativeDataHandler(client, mMethodChannel, command)); 240 | } 241 | } 242 | 243 | - (NSString *)getName { 244 | return METHOD_INIT; 245 | } 246 | @end 247 | 248 | //====================================================== 249 | @implementation EzyConnectMethod 250 | 251 | -(void)validate:(NSDictionary *)params { 252 | if(![params valueForKey:@"host"]) 253 | [NSException raise:NSInvalidArgumentException format:@"must specific host"]; 254 | if(![params valueForKey:@"port"]) 255 | [NSException raise:NSInvalidArgumentException format:@"must specific port"]; 256 | } 257 | 258 | - (NSObject *)invoke:(NSDictionary *)params { 259 | NSString* host = [params valueForKey:@"host"]; 260 | NSNumber* port = [params valueForKey:@"port"]; 261 | EzyClient* client = getClient(params); 262 | client->connect([host UTF8String], [port intValue]); 263 | return [NSNumber numberWithBool:TRUE]; 264 | } 265 | 266 | - (NSString *)getName { 267 | return METHOD_CONNECT; 268 | } 269 | 270 | @end 271 | 272 | //====================================================== 273 | @implementation EzyReconnectMethod 274 | 275 | - (NSObject *)invoke:(NSDictionary *)params { 276 | EzyClient* client = getClient(params); 277 | bool answer = client->reconnect(); 278 | return [NSNumber numberWithBool:answer]; 279 | } 280 | 281 | - (NSString *)getName { 282 | return METHOD_RECONNECT; 283 | } 284 | @end 285 | 286 | //====================================================== 287 | @implementation EzyDisconnectMethod 288 | 289 | - (NSObject *)invoke:(NSDictionary *)params { 290 | EzyClient* client = getClient(params); 291 | int reason = constant::Close; 292 | if([params valueForKey:@"reason"]) 293 | reason = [[params valueForKey:@"reason"] intValue]; 294 | client->disconnect(reason); 295 | return [NSNumber numberWithBool:TRUE]; 296 | } 297 | 298 | - (NSString *)getName { 299 | return METHOD_DISCONNECT; 300 | } 301 | @end 302 | 303 | //====================================================== 304 | @implementation EzySendMethod 305 | 306 | - (NSObject *)invoke:(NSDictionary *)params { 307 | NSDictionary* request = [params objectForKey:@"request"]; 308 | if(!request) { 309 | @throw [NSException exceptionWithName:@"NSInvalidArgumentException" 310 | reason:@"must specific request to send to server" 311 | userInfo:nil]; 312 | } 313 | EzyClient* client = getClient(params); 314 | NSString* cmd = [request objectForKey:@"command"]; 315 | NSArray* data = [request objectForKey:@"data"]; 316 | NSNumber* encrypted = [request objectForKey:@"encrypted"]; 317 | EzyArray* array = (EzyArray*)[EzyNativeSerializers fromReadableArray:data]; 318 | EzyCommand command = sNativeCommandIds[[cmd UTF8String]]; 319 | client->send(command, array, [encrypted boolValue]); 320 | return [NSNumber numberWithBool:TRUE]; 321 | } 322 | 323 | - (NSString *)getName { 324 | return METHOD_SEND; 325 | } 326 | @end 327 | 328 | //====================================================== 329 | @implementation EzySetStatusMethod 330 | 331 | - (NSObject *)invoke:(NSDictionary *)params { 332 | EzyClient* client = getClient(params); 333 | NSString* statusName = [params valueForKey:@"status"]; 334 | EzyConnectionStatus status = sNativeConnectionStatusIds[[statusName UTF8String]]; 335 | client->setStatus(status); 336 | return [NSNumber numberWithBool:TRUE]; 337 | } 338 | 339 | - (NSString *)getName { 340 | return METHOD_SET_STATUS; 341 | } 342 | @end 343 | 344 | //====================================================== 345 | @implementation EzyStartPingScheduleMethod 346 | 347 | - (NSObject *)invoke:(NSDictionary *)params { 348 | EzyClient* client = getClient(params); 349 | EzyPingSchedule* pingSchedule = client->getPingSchedule(); 350 | pingSchedule->start(); 351 | return [NSNumber numberWithBool:TRUE]; 352 | } 353 | 354 | - (NSString *)getName { 355 | return METHOD_START_PING_SCHEDULE; 356 | } 357 | @end 358 | 359 | //====================================================== 360 | @implementation EzyGenerateKeyPairMethod 361 | 362 | - (NSObject *)invoke:(NSDictionary *)params { 363 | EzyKeyPairProxy* keyPair = [[EzyRSAProxy getInstance] generateKeyPair]; 364 | NSString* publicKey = [keyPair publicKey]; 365 | NSData* privateKey = [[keyPair privateKey] dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO]; 366 | NSDictionary* answer = [NSMutableDictionary dictionary]; 367 | [answer setValue:publicKey forKey:@"publicKey"]; 368 | [answer setValue:[FlutterStandardTypedData typedDataWithBytes:privateKey] forKey:@"privateKey"]; 369 | return answer; 370 | } 371 | 372 | - (NSString *)getName { 373 | return METHOD_GENERATE_KEY_PAIR; 374 | } 375 | @end 376 | 377 | //====================================================== 378 | @implementation EzyRsaDecryptMethod 379 | 380 | - (NSObject *)invoke:(NSDictionary *)params { 381 | FlutterStandardTypedData* data = params[@"message"]; 382 | FlutterStandardTypedData* privateKey = params[@"privateKey"]; 383 | NSData* decryption = [[EzyRSAProxy getInstance] decrypt: [data data] 384 | privateKey:[privateKey data]]; 385 | return [FlutterStandardTypedData typedDataWithBytes:decryption]; 386 | } 387 | 388 | - (NSString *)getName { 389 | return METHOD_RSA_DECRYPT; 390 | } 391 | 392 | @end 393 | 394 | //====================================================== 395 | @implementation EzyLogMethod 396 | 397 | - (NSObject *)invoke:(NSDictionary *)params { 398 | NSString* message = params[@"message"]; 399 | NSLog(@"%@", message); 400 | return [NSNumber numberWithBool:TRUE]; 401 | } 402 | 403 | - (NSString *)getName { 404 | return METHOD_LOG; 405 | } 406 | @end 407 | 408 | //====================================================== 409 | @implementation EzySetSessionKeyMethod 410 | 411 | - (NSObject *)invoke:(NSDictionary *)params { 412 | EzyClient* client = getClient(params); 413 | FlutterStandardTypedData* flutterSessionKey = params[@"sessionKey"]; 414 | NSData* sessionKey = [flutterSessionKey data]; 415 | client->setSessionKey(std::string((char*)[sessionKey bytes], (int)[sessionKey length])); 416 | return [NSNumber numberWithBool:TRUE]; 417 | } 418 | 419 | - (NSString *)getName { 420 | return METHOD_SET_SESSION_KEY; 421 | } 422 | @end 423 | -------------------------------------------------------------------------------- /ios/EzyClient/serializer/EzyClientConfigSerializer.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyClientConfigSerializer.h 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface EzyClientConfigSerializer : NSObject 14 | -(NSDictionary*)serialize:(void*)value; 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /ios/EzyClient/serializer/EzyClientConfigSerializer.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyClientConfigSerializer.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import "EzyClientConfigSerializer.h" 10 | #import "EzyHeaders.h" 11 | #import "../util/EzyNativeStrings.h" 12 | 13 | EZY_USING_NAMESPACE::config; 14 | 15 | @implementation EzyClientConfigSerializer 16 | - (NSDictionary *)serialize:(void *)value { 17 | EzyClientConfig* config = (EzyClientConfig*)value; 18 | NSDictionary* dict = [NSMutableDictionary dictionary]; 19 | [dict setValue:[EzyNativeStrings newNSString:config->getClientName().c_str()] forKey:@"clientName"]; 20 | [dict setValue:[EzyNativeStrings newNSString:config->getZoneName().c_str()] forKey:@"zoneName"]; 21 | 22 | EzyPingConfig* pingConfig = config->getPing(); 23 | NSDictionary* pingDict = [NSMutableDictionary dictionary]; 24 | [pingDict setValue:[NSNumber numberWithInt:pingConfig->getPingPeriod()] forKey:@"pingPeriod"]; 25 | [pingDict setValue:[NSNumber numberWithInt:pingConfig->getMaxLostPingCount()] forKey:@"maxLostPingCount"]; 26 | [dict setValue:pingDict forKey:@"ping"]; 27 | 28 | NSDictionary* reconnectDict = [NSMutableDictionary dictionary]; 29 | EzyReconnectConfig* reconnectConfig = config->getReconnect(); 30 | [reconnectDict setValue:[NSNumber numberWithInt:reconnectConfig->getMaxReconnectCount()] forKey:@"maxReconnectCount"]; 31 | [reconnectDict setValue:[NSNumber numberWithInt:reconnectConfig->getReconnectPeriod()] forKey:@"reconnectPeriod"]; 32 | [reconnectDict setValue:[NSNumber numberWithInt:reconnectConfig->isEnable()] forKey:@"enable"]; 33 | [dict setValue:reconnectDict forKey:@"reconnect"]; 34 | 35 | return dict; 36 | } 37 | @end 38 | -------------------------------------------------------------------------------- /ios/EzyClient/serializer/EzyEventSerializer.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyEventSerializer.h 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/26/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface EzyEventSerializer : NSObject 14 | 15 | -(NSDictionary*)serialize: (void*)value; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /ios/EzyClient/serializer/EzyEventSerializer.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyEventSerializer.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/26/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import "EzyEventSerializer.h" 10 | #include "EzyHeaders.h" 11 | 12 | EZY_USING_NAMESPACE::event; 13 | EZY_USING_NAMESPACE::constant; 14 | 15 | @implementation EzyEventSerializer 16 | 17 | -(NSDictionary *)serialize:(void *)value { 18 | EzyEvent* event = (EzyEvent*)value; 19 | switch (event->getType()) { 20 | case ConnectionSuccess: 21 | return [NSMutableDictionary dictionary]; 22 | case ConnectionFailure: 23 | return [self serializeConnectionFailureEvent:event]; 24 | case Disconnection: 25 | return [self serializeConnectionFailureEvent:event]; 26 | case LostPing: 27 | return [self serializeLostPingEvent:event]; 28 | case TryConnect: 29 | return [self serializeTryConnectEvent:event]; 30 | default: 31 | break; 32 | } 33 | @throw [NSException exceptionWithName:@"NSInvalidArgumentException" reason:@"has no serializer with event" userInfo:nil]; 34 | } 35 | 36 | -(NSDictionary*)serializeConnectionFailureEvent: (EzyEvent*)event { 37 | EzyConnectionFailureEvent* mevent = (EzyConnectionFailureEvent*)event; 38 | NSDictionary* dict = [NSMutableDictionary dictionary]; 39 | NSNumber* reason = [NSNumber numberWithInt: mevent->getReason()]; 40 | [dict setValue:reason forKey:@"reason"]; 41 | return dict; 42 | } 43 | 44 | -(NSDictionary*)serializeDisconnectionEvent: (EzyEvent*)event { 45 | EzyDisconnectionEvent* mevent = (EzyDisconnectionEvent*)event; 46 | NSDictionary* dict = [NSMutableDictionary dictionary]; 47 | NSNumber* reason = [NSNumber numberWithInt: mevent->getReason()]; 48 | [dict setValue:reason forKey:@"reason"]; 49 | return dict; 50 | } 51 | 52 | -(NSDictionary*)serializeLostPingEvent: (EzyEvent*)event { 53 | EzyLostPingEvent* mevent = (EzyLostPingEvent*)event; 54 | NSDictionary* dict = [NSMutableDictionary dictionary]; 55 | int count = mevent->getCount(); 56 | [dict setValue:[NSNumber numberWithInt:count] forKey:@"count"]; 57 | return dict; 58 | } 59 | 60 | -(NSDictionary*)serializeTryConnectEvent: (EzyEvent*)event { 61 | EzyTryConnectEvent* mevent = (EzyTryConnectEvent*)event; 62 | NSDictionary* dict = [NSMutableDictionary dictionary]; 63 | int count = mevent->getCount(); 64 | [dict setValue:[NSNumber numberWithInt:count] forKey:@"count"]; 65 | return dict; 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /ios/EzyClient/serializer/EzyNativeDataDeserializer.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyNativeDataDeserializer.h 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface EzyNativeDataDeserializer : NSObject 14 | -(void*)fromReadableArray:(NSArray*)value; 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /ios/EzyClient/serializer/EzyNativeDataDeserializer.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyNativeDataDeserializer.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EzyNativeDataDeserializer.h" 11 | #import "../math/EzyNSNumber.h" 12 | #import "../util/NSByteArray.h" 13 | #include "EzyHeaders.h" 14 | 15 | EZY_USING_NAMESPACE::entity; 16 | 17 | @implementation EzyNativeDataDeserializer 18 | - (void *)fromReadableArray:(NSArray *)value { 19 | EzyArray* array = new EzyArray(); 20 | if(value) { 21 | for(id item in value) 22 | [self deserializeToArray:array value:item]; 23 | } 24 | return array; 25 | } 26 | 27 | - (void *) fromReadableMap: (NSDictionary*)value { 28 | EzyObject* object = new EzyObject(); 29 | if(value) { 30 | for(id key in value) { 31 | NSObject* val = [value valueForKey:key]; 32 | [self deserializeToObject:object key:key value:val]; 33 | } 34 | } 35 | return object; 36 | } 37 | 38 | - (void)deserializeToArray:(EzyArray*)output value:(NSObject*)value { 39 | if([value isKindOfClass:[NSNumber class]]) { 40 | EzyPrimitive* item = [self deserializeToPrimitive:value]; 41 | output->addItem(item); 42 | } 43 | else if([value isKindOfClass:[EzyNSNumber class]]) { 44 | EzyNSNumber* number = (EzyNSNumber*)value; 45 | EzyPrimitive* item = [self deserializeToNumber:number]; 46 | output->addItem(item); 47 | } 48 | else if([value isKindOfClass:[NSString class]]) { 49 | NSString* string = (NSString*)value; 50 | output->addString([string UTF8String]); 51 | } 52 | else if([value isKindOfClass:[NSByteArray class]]) { 53 | NSByteArray* byteArray = (NSByteArray*)value; 54 | output->addByteArray(std::string((char*)byteArray.data.bytes, byteArray.size)); 55 | } 56 | else if([value isKindOfClass:[NSArray class]]) { 57 | NSArray* array = (NSArray*)value; 58 | EzyArray* farray = (EzyArray*)[self fromReadableArray:array]; 59 | output->addArray(farray); 60 | } 61 | else if([value isKindOfClass:[NSDictionary class]]) { 62 | NSDictionary* dict = (NSDictionary*)value; 63 | EzyObject* fobject = (EzyObject*)[self fromReadableMap:dict]; 64 | output->addObject(fobject); 65 | } 66 | else if([value isKindOfClass:[NSNull class]]) { 67 | output->addNull(); 68 | } 69 | else if([value isKindOfClass:[FlutterStandardTypedData class]]) { 70 | FlutterStandardTypedData* data = (FlutterStandardTypedData*)value; 71 | FlutterStandardDataType dataType = [data type]; 72 | if(dataType == FlutterStandardDataTypeUInt8) { 73 | NSData* realData = [data data]; 74 | output->addByteArray(std::string((char*)[realData bytes], [realData length])); 75 | } 76 | else { 77 | output->addArray([self deserializeFlutterDataToArray:data]); 78 | } 79 | } 80 | else { 81 | @throw [NSException exceptionWithName:@"NSInvalidArgumentException" 82 | reason: [NSString stringWithFormat:@"has no deserializer for value: %@", value] 83 | userInfo:nil]; 84 | } 85 | } 86 | 87 | - (void)deserializeToObject:(EzyObject*)output key:(NSString*)key value:(NSObject*)value { 88 | std::string k = [key UTF8String]; 89 | if([value isKindOfClass:[NSNumber class]]) { 90 | EzyPrimitive* item = [self deserializeToPrimitive:value]; 91 | output->addItem(k, item); 92 | } 93 | else if([value isKindOfClass:[EzyNSNumber class]]) { 94 | EzyNSNumber* number = (EzyNSNumber*)value; 95 | EzyPrimitive* item = [self deserializeToNumber:number]; 96 | output->addItem(k, item); 97 | } 98 | else if([value isKindOfClass:[NSString class]]) { 99 | NSString* string = (NSString*)value; 100 | output->setString(k, [string UTF8String]); 101 | } 102 | else if([value isKindOfClass:[NSArray class]]) { 103 | NSArray* array = (NSArray*)value; 104 | EzyArray* farray = (EzyArray*)[self fromReadableArray:array]; 105 | output->setArray(k, farray); 106 | } 107 | else if([value isKindOfClass:[NSDictionary class]]) { 108 | NSDictionary* dict = (NSDictionary*)value; 109 | EzyObject* fobject = (EzyObject*)[self fromReadableMap:dict]; 110 | output->setObject(k, fobject); 111 | } 112 | else if([value isKindOfClass:[NSNull class]]) { 113 | // do nothing 114 | } 115 | else if([value isKindOfClass:[FlutterStandardTypedData class]]) { 116 | FlutterStandardTypedData* data = (FlutterStandardTypedData*)value; 117 | FlutterStandardDataType dataType = [data type]; 118 | if(dataType == FlutterStandardDataTypeUInt8) { 119 | NSData* realData = [data data]; 120 | output->setByteArray(k, std::string((char*)[realData bytes], [realData length])); 121 | } 122 | else { 123 | output->setArray(k, [self deserializeFlutterDataToArray:data]); 124 | } 125 | } 126 | else { 127 | @throw [NSException exceptionWithName:@"NSInvalidArgumentException" 128 | reason: [NSString stringWithFormat:@"has no deserializer for key: %@, value: %@", key, value] 129 | userInfo:nil]; 130 | } 131 | } 132 | 133 | -(EzyArray*)deserializeFlutterDataToArray:(FlutterStandardTypedData*)data { 134 | EzyArray *array = new EzyArray(); 135 | FlutterStandardDataType dataType = [data type]; 136 | if(dataType == FlutterStandardDataTypeInt32) { 137 | NSData* realData = [data data]; 138 | int32_t* int32Array = (int32_t*)[realData bytes]; 139 | for(int i = 0 ; i < [realData length] ; ++i) { 140 | array->addInt(int32Array[i]); 141 | } 142 | } 143 | else if(dataType == FlutterStandardDataTypeInt64) { 144 | NSData* realData = [data data]; 145 | int64_t* int64Array = (int64_t*)[realData bytes]; 146 | for(int i = 0 ; i < [realData length] ; ++i) { 147 | array->addInt(int64Array[i]); 148 | } 149 | } 150 | else if(dataType == FlutterStandardDataTypeFloat32) { 151 | NSData* realData = [data data]; 152 | float* floatArray = (float*)[realData bytes]; 153 | for(int i = 0 ; i < [realData length] ; ++i) { 154 | array->addFloat(floatArray[i]); 155 | } 156 | } 157 | else { 158 | NSData* realData = [data data]; 159 | double* doubleArray = (double*)[realData bytes]; 160 | for(int i = 0 ; i < [realData length] ; ++i) { 161 | array->addDouble(doubleArray[i]); 162 | } 163 | } 164 | return array; 165 | } 166 | 167 | -(EzyPrimitive*)deserializeToNumber:(EzyNSNumber*)value { 168 | EzyPrimitive* item = new EzyPrimitive(); 169 | switch ([value getType]) { 170 | case NUMBER_TYPE_BOOL: 171 | item->setBool([value boolValue]); 172 | break; 173 | case NUMBER_TYPE_DOUBLE: 174 | item->setDouble([value doubleValue]); 175 | break; 176 | case NUMBER_TYPE_FLOAT: 177 | item->setFloat([value floatValue]); 178 | break; 179 | case NUMBER_TYPE_INT: 180 | item->setInt([value intValue]); 181 | break; 182 | case NUMBER_TYPE_UINT: 183 | item->setInt([value uintValue]); 184 | break; 185 | default: 186 | break; 187 | } 188 | return item; 189 | }; 190 | 191 | -(EzyPrimitive*)deserializeToPrimitive:(NSObject*)value { 192 | NSNumber* number = (NSNumber*)value; 193 | EzyPrimitive* item = new EzyPrimitive(); 194 | CFNumberType numberType = CFNumberGetType((CFNumberRef)number); 195 | if(numberType == kCFNumberSInt8Type) { 196 | item->setInt([number intValue]); 197 | } 198 | else if(numberType == kCFNumberSInt16Type) { 199 | item->setInt([number intValue]); 200 | } 201 | else if(numberType == kCFNumberSInt32Type) { 202 | item->setInt([number longValue]); 203 | } 204 | else if(numberType == kCFNumberSInt64Type) { 205 | item->setInt([number longLongValue]); 206 | } 207 | else if(numberType == kCFNumberFloat32Type) { 208 | item->setInt([number floatValue]); 209 | } 210 | else if(numberType == kCFNumberFloat64Type) { 211 | item->setInt([number doubleValue]); 212 | } 213 | else if(numberType == kCFNumberCharType) { 214 | if([number isEqual: @(YES)] || [number isEqual: @(NO)]) { 215 | item->setBool([number boolValue]); 216 | } 217 | else { 218 | item->setInt([number intValue]); 219 | } 220 | } 221 | else if(numberType == kCFNumberShortType) { 222 | item->setInt([number intValue]); 223 | } 224 | else if(numberType == kCFNumberIntType) { 225 | item->setInt([number longValue]); 226 | } 227 | else if(numberType == kCFNumberLongType) { 228 | item->setInt([number longLongValue]); 229 | } 230 | else if(numberType == kCFNumberLongLongType) { 231 | item->setInt([number longLongValue]); 232 | } 233 | else if(numberType == kCFNumberFloatType) { 234 | item->setInt([number floatValue]); 235 | } 236 | else if(numberType == kCFNumberDoubleType) { 237 | item->setInt([number doubleValue]); 238 | } 239 | else if(numberType == kCFNumberCFIndexType) { 240 | item->setInt([number longLongValue]); 241 | } 242 | else if(numberType == kCFNumberNSIntegerType) { 243 | item->setInt([number longLongValue]); 244 | } 245 | else if(numberType == kCFNumberCGFloatType) { 246 | item->setInt([number floatValue]); 247 | } 248 | else if(numberType == kCFNumberMaxType) { 249 | item->setInt([number longLongValue]); 250 | } 251 | else { 252 | @throw [NSException exceptionWithName:@"NSInvalidArgumentException" 253 | reason: [NSString stringWithFormat:@"can deserialize number: %@ with type: %d", number, (int)numberType] 254 | userInfo:nil]; 255 | } 256 | return item; 257 | }; 258 | @end 259 | -------------------------------------------------------------------------------- /ios/EzyClient/serializer/EzyNativeDataSerializer.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyNativeDataSerializer.h 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface EzyNativeDataSerializer : NSObject 14 | -(NSArray*)toWritableArray:(void*)arrayValue; 15 | -(NSDictionary*)toWritableMap:(void*)objectValue; 16 | -(void)serialize:(NSMutableArray*)output value:(void*)value; 17 | -(void)serialize:(NSDictionary*)output key:(const void*)key value:(void*)value; 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /ios/EzyClient/serializer/EzyNativeDataSerializer.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyNativeDataSerializer.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import "EzyNativeDataSerializer.h" 10 | #include "EzyHeaders.h" 11 | #import "../util/EzyNativeStrings.h" 12 | 13 | EZY_USING_NAMESPACE; 14 | EZY_USING_NAMESPACE::entity; 15 | 16 | @implementation EzyNativeDataSerializer 17 | 18 | -(NSArray*)toWritableArray:(void*)arrayValue { 19 | EzyArray* value = (EzyArray*)arrayValue; 20 | NSMutableArray* answer = [NSMutableArray array]; 21 | if(value) { 22 | for (int i = 0; i < value->size(); ++i) { 23 | EzyValue* item = value->getItem(i); 24 | [self serialize:answer value:item]; 25 | } 26 | } 27 | return answer; 28 | } 29 | 30 | -(NSDictionary*)toWritableMap:(void*)objectValue { 31 | EzyObject* value = (EzyObject*)objectValue; 32 | NSDictionary* answer = [NSMutableDictionary dictionary]; 33 | if(value) { 34 | std::vector keys = value->getKeys(); 35 | for(int i = 0 ; i < keys.size() ; ++i) { 36 | EzyValue* val = value->getItem(keys[i]); 37 | [self serialize:answer key:keys[i].c_str() value:val]; 38 | } 39 | } 40 | return answer; 41 | } 42 | 43 | -(void)serialize:(NSMutableArray*)output value:(void*)value { 44 | if(value) { 45 | NSObject* svalue = [self serializeValue:(EzyValue*)value]; 46 | if(svalue) 47 | [output addObject:svalue]; 48 | else 49 | [output addObject:[NSNull null]]; 50 | } 51 | else { 52 | [output addObject:[NSNull null]]; 53 | } 54 | } 55 | 56 | -(void)serialize:(NSDictionary*)output key:(const void*)key value:(void*)value { 57 | if(value) { 58 | NSObject* svalue = [self serializeValue:(EzyValue*)value]; 59 | NSString* skey = [EzyNativeStrings newNSString:(const char*)key]; 60 | [output setValue:svalue forKey:skey]; 61 | } 62 | } 63 | 64 | -(NSObject*)serializeValue:(EzyValue*)value { 65 | switch (value->getType()) { 66 | case TypeBool: 67 | return [NSNumber numberWithBool:((EzyPrimitive*)value)->getBool()]; 68 | case TypeFloat: 69 | return [NSNumber numberWithFloat:((EzyPrimitive*)value)->getFloat()]; 70 | case TypeDouble: 71 | return [NSNumber numberWithDouble:((EzyPrimitive*)value)->getDouble()]; 72 | case TypeInt: 73 | return [NSNumber numberWithLong:((EzyPrimitive*)value)->getInt()]; 74 | case TypeUInt: 75 | return [NSNumber numberWithUnsignedLong:((EzyPrimitive*)value)->getUInt()]; 76 | case TypeString: 77 | return [NSString stringWithUTF8String:((EzyString*)value)->getString().c_str()]; 78 | case TypeByteArray: 79 | return [NSData dataWithBytes:((EzyByteArray*)value)->getData().c_str() 80 | length:((EzyByteArray*)value)->getData().length()]; 81 | case TypeDict: 82 | return [self toWritableMap:value]; 83 | case TypeArray: 84 | return [self toWritableArray:value]; 85 | default: 86 | break; 87 | } 88 | return nil; 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /ios/EzyClient/serializer/EzyNativeSerializers.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyNativeSerializers.h 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface EzyNativeSerializers : NSObject 14 | +(NSDictionary*)serializeEvent:(void*)event; 15 | +(NSDictionary*)serializeClientConfig:(void*)clientConfig; 16 | +(NSArray*)toWritableArray:(void*)arrayValue; 17 | +(void*)fromReadableArray:(NSArray*)value; 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /ios/EzyClient/serializer/EzyNativeSerializers.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyNativeSerializers.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import "EzyNativeSerializers.h" 10 | #import "EzyEventSerializer.h" 11 | #import "EzyClientConfigSerializer.h" 12 | #import "EzyNativeDataSerializer.h" 13 | #import "EzyNativeDataDeserializer.h" 14 | 15 | static EzyEventSerializer* sEventSerializer = [[EzyEventSerializer alloc] init]; 16 | static EzyClientConfigSerializer* sClientConfigSerializer = [[EzyClientConfigSerializer alloc] init]; 17 | static EzyNativeDataSerializer* sNativeDataSerializer = [[EzyNativeDataSerializer alloc] init]; 18 | static EzyNativeDataDeserializer* sNativeDataDeserializer = [[EzyNativeDataDeserializer alloc] init]; 19 | 20 | @implementation EzyNativeSerializers 21 | +(NSDictionary *)serializeEvent:(void *)event { 22 | NSDictionary* answer = [sEventSerializer serialize:event]; 23 | return answer; 24 | } 25 | 26 | + (NSDictionary *)serializeClientConfig:(void *)clientConfig { 27 | NSDictionary* answer = [sClientConfigSerializer serialize:clientConfig]; 28 | return answer; 29 | } 30 | 31 | +(NSArray *)toWritableArray:(void *)arrayValue { 32 | NSArray* answer = [sNativeDataSerializer toWritableArray:arrayValue]; 33 | return answer; 34 | } 35 | 36 | + (void *)fromReadableArray:(NSArray *)value { 37 | void* answer = [sNativeDataDeserializer fromReadableArray:value]; 38 | return answer; 39 | } 40 | @end 41 | -------------------------------------------------------------------------------- /ios/EzyClient/util/EzyNativeStrings.h: -------------------------------------------------------------------------------- 1 | // 2 | // EzyNativeStrings.h 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface EzyNativeStrings : NSObject 14 | 15 | +(NSString*)newNSString: (const char*)str; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /ios/EzyClient/util/EzyNativeStrings.mm: -------------------------------------------------------------------------------- 1 | // 2 | // EzyNativeStrings.m 3 | // ezyfox-server-react-native-client 4 | // 5 | // Created by Dung Ta Van on 10/27/18. 6 | // Copyright © 2018 Young Monkeys. All rights reserved. 7 | // 8 | 9 | #import "EzyNativeStrings.h" 10 | 11 | @implementation EzyNativeStrings 12 | 13 | + (NSString *)newNSString:(const char *)str { 14 | return [NSString stringWithCString:str encoding:[NSString defaultCStringEncoding]]; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /ios/EzyClient/util/NSByArray.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSByArray.m 3 | // ezyfox-ssl 4 | // 5 | // Created by Dzung on 01/06/2021. 6 | // 7 | 8 | #import 9 | #import "NSByteArray.h" 10 | 11 | @implementation NSByteArray { 12 | } 13 | 14 | +(id)byteArrayWithData: (NSData*)data { 15 | NSByteArray* pRet = [[NSByteArray alloc] init]; 16 | pRet.data = data; 17 | pRet.size = (int)[data length]; 18 | return pRet; 19 | } 20 | 21 | +(id)byteArrayWithCharArray:(const char *)data size:(int)size { 22 | NSByteArray* pRet = [[NSByteArray alloc] init]; 23 | pRet.data = [NSData dataWithBytes:data length:size]; 24 | pRet.size = size; 25 | return pRet; 26 | } 27 | @end 28 | -------------------------------------------------------------------------------- /ios/EzyClient/util/NSByteArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSByteArray.h 3 | // ezyfox-ssl 4 | // 5 | // Created by Dzung on 01/06/2021. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NSByteArray : NSObject 13 | 14 | @property const NSData* data; 15 | @property int size; 16 | 17 | +(id)byteArrayWithData: (NSData*)data; 18 | 19 | +(id)byteArrayWithCharArray: (const char*)data size: (int)size; 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /ios/ezyfox_server_flutter_client.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint ezyfox_server_flutter_client.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'ezyfox_server_flutter_client' 7 | s.version = '0.0.1' 8 | s.summary = 'EzyFox Server's Flutter client sdk.' 9 | s.description = <<-DESC 10 | EzyFox Server's Flutter client sdk. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'youngmonkeys.org' => 'https://youngmonkeys.org' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'EzyClient/**/*' 17 | s.public_header_files = 'EzyClient/**/*.h' 18 | s.dependency 'Flutter' 19 | s.platform = :ios, '8.0' 20 | 21 | # Flutter.framework does not contain a i386 slice. 22 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 23 | end 24 | -------------------------------------------------------------------------------- /lib/ezy_client.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'ezy_config.dart'; 4 | import 'ezy_constants.dart'; 5 | import 'ezy_entities.dart'; 6 | import 'ezy_logger.dart'; 7 | import 'ezy_managers.dart'; 8 | import 'ezy_proxy.dart'; 9 | import 'ezy_setup.dart'; 10 | 11 | class EzyClient { 12 | late bool enableSSL; 13 | late bool enableDebug; 14 | late EzyConfig config; 15 | late String name; 16 | late EzyZone? zone; 17 | late EzyUser? me; 18 | late EzySetup setup; 19 | late EzyHandlerManager handlerManager; 20 | late Uint8List? privateKey; 21 | late int sessionId; 22 | late String? sessionToken; 23 | late Uint8List? sessionKey; 24 | 25 | EzyClient(this.config) { 26 | EzyProxy.run("init", config.toMap()); 27 | name = config.getClientName(); 28 | enableSSL = config.enableSSL; 29 | enableDebug = config.enableDebug; 30 | handlerManager = EzyHandlerManager.create(this); 31 | setup = EzySetup(handlerManager); 32 | } 33 | 34 | void connect(String host, int port) { 35 | privateKey = null; 36 | sessionKey = null; 37 | var params = Map(); 38 | params["clientName"] = name; 39 | params["host"] = host; 40 | params["port"] = port; 41 | EzyProxy.run("connect", params); 42 | } 43 | 44 | Future reconnect() { 45 | privateKey = null; 46 | sessionKey = null; 47 | var params = Map(); 48 | params["clientName"] = name; 49 | return EzyProxy.run("reconnect", params); 50 | } 51 | 52 | void disconnect([int reason = EzyDisconnectReason.CLOSE]) { 53 | var params = Map(); 54 | params["clientName"] = name; 55 | params["reason"] = reason; 56 | EzyProxy.run("disconnect", params); 57 | } 58 | 59 | void close() { 60 | disconnect(); 61 | } 62 | 63 | void send(String cmd, dynamic data, [bool encrypted = false]) { 64 | var shouldEncrypted = encrypted; 65 | if (encrypted && sessionKey == null) { 66 | if (enableDebug) { 67 | shouldEncrypted = false; 68 | } else { 69 | EzyLogger.error( 70 | "can not send command: $cmd, you must enable SSL " 71 | "or enable debug mode by configuration when you create the client", 72 | ); 73 | return; 74 | } 75 | } 76 | var params = Map(); 77 | params["clientName"] = name; 78 | var requestParams = Map(); 79 | requestParams["command"] = cmd; 80 | requestParams["data"] = data; 81 | requestParams["encrypted"] = shouldEncrypted; 82 | params["request"] = requestParams; 83 | EzyProxy.run("send", params); 84 | } 85 | 86 | void startPingSchedule() { 87 | var params = Map(); 88 | params["clientName"] = name; 89 | EzyProxy.run("startPingSchedule", params); 90 | } 91 | 92 | void setStatus(String status) { 93 | var params = Map(); 94 | params["clientName"] = name; 95 | params["status"] = status; 96 | EzyProxy.run("setStatus", params); 97 | } 98 | 99 | void setSessionKey(Uint8List sessionKey) { 100 | this.sessionKey = sessionKey; 101 | var params = Map(); 102 | params["clientName"] = name; 103 | params["sessionKey"] = sessionKey; 104 | EzyProxy.run("setSessionKey", params); 105 | } 106 | 107 | EzyApp? getApp() { 108 | if (zone != null) { 109 | var appManager = zone!.appManager; 110 | var app = appManager.getApp(); 111 | return app; 112 | } 113 | return null; 114 | } 115 | 116 | EzyApp? getAppById(int appId) { 117 | if (zone != null) { 118 | var appManager = zone!.appManager; 119 | var app = appManager.getAppById(appId); 120 | return app; 121 | } 122 | return null; 123 | } 124 | 125 | void handleEvent(String eventType, Map data) { 126 | var eventHandlers = handlerManager.eventHandlers; 127 | eventHandlers.handle(eventType, data); 128 | } 129 | 130 | void handleData(String command, List data) { 131 | var dataHandlers = handlerManager.dataHandlers; 132 | dataHandlers.handle(command, data); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /lib/ezy_clients.dart: -------------------------------------------------------------------------------- 1 | import 'ezy_client.dart'; 2 | import 'ezy_config.dart'; 3 | 4 | class EzyClients { 5 | late String defaultClientName; 6 | late Map clients; 7 | static final EzyClients _INSTANCE = EzyClients._(); 8 | 9 | EzyClients._() { 10 | defaultClientName = ""; 11 | clients = {}; 12 | } 13 | 14 | static EzyClients getInstance() { 15 | return _INSTANCE; 16 | } 17 | 18 | EzyClient newClient(EzyConfig config) { 19 | var client = EzyClient(config); 20 | addClient(client); 21 | if (defaultClientName == "") { 22 | defaultClientName = client.name; 23 | } 24 | return client; 25 | } 26 | 27 | EzyClient newDefaultClient(EzyConfig config) { 28 | var client = newClient(config); 29 | defaultClientName = client.name; 30 | return client; 31 | } 32 | 33 | void addClient(EzyClient client) { 34 | clients[client.name] = client; 35 | } 36 | 37 | EzyClient getClient(String clientName) { 38 | var client = clients[clientName]!; 39 | return client; 40 | } 41 | 42 | EzyClient getDefaultClient() { 43 | return clients[defaultClientName]!; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/ezy_codec.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'ezy_proxy.dart'; 4 | 5 | class EzyKeyPairProxy { 6 | late String publicKey; 7 | late Uint8List privateKey; 8 | 9 | EzyKeyPairProxy(this.publicKey, this.privateKey); 10 | } 11 | 12 | class EzyRSAProxy { 13 | static final EzyRSAProxy _INSTANCE = EzyRSAProxy._(); 14 | 15 | EzyRSAProxy._(); 16 | 17 | static EzyRSAProxy getInstance() { 18 | return _INSTANCE; 19 | } 20 | 21 | void _onKeyPairGenerated(Map result, Function(EzyKeyPairProxy) callback) { 22 | callback(EzyKeyPairProxy(result["publicKey"], result["privateKey"])); 23 | } 24 | 25 | void generateKeyPair(Function(EzyKeyPairProxy) callback) { 26 | EzyProxy.run("generateKeyPair", {}).then((result) => { 27 | _onKeyPairGenerated(result, callback) 28 | }); 29 | } 30 | 31 | void decrypt( 32 | Uint8List message, 33 | Uint8List privateKey, Function(Uint8List) callback) { 34 | Map params = { 35 | "message": message, 36 | "privateKey": privateKey 37 | }; 38 | EzyProxy.run("rsaDecrypt", params).then((result) => { 39 | callback(result) 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/ezy_config.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | class EzyConfig { 4 | late String zoneName = ""; 5 | late String clientName; 6 | late bool enableSSL = false; 7 | late bool enableDebug = false; 8 | late EzyPingConfig ping = EzyPingConfig(); 9 | late EzyReconnectConfig reconnect = EzyReconnectConfig(); 10 | 11 | String getClientName() { 12 | if(clientName == null) 13 | return zoneName; 14 | return clientName; 15 | } 16 | 17 | Map toMap() { 18 | Map map = Map(); 19 | map["clientName"] = getClientName(); 20 | map["zoneName"] = zoneName; 21 | map["enableSSL"] = enableSSL; 22 | map["enableDebug"] = enableDebug; 23 | map["ping"] = ping.toMap(); 24 | map["reconnect"] = reconnect.toMap(); 25 | return map; 26 | } 27 | } 28 | 29 | class EzyPingConfig { 30 | late int pingPeriod = 3000; 31 | late int maxLostPingCount = 5; 32 | 33 | Map toMap() { 34 | Map map = Map(); 35 | map["pingPeriod"] = pingPeriod; 36 | map["maxLostPingCount"] = maxLostPingCount; 37 | return map; 38 | } 39 | } 40 | 41 | class EzyReconnectConfig { 42 | late bool enable = true; 43 | late int maxReconnectCount = 5; 44 | late int reconnectPeriod = 3000; 45 | 46 | Map toMap() { 47 | Map map = Map(); 48 | map["enable"] = enable; 49 | map["maxReconnectCount"] = maxReconnectCount; 50 | map["reconnectPeriod"] = reconnectPeriod; 51 | return map; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/ezy_constants.dart: -------------------------------------------------------------------------------- 1 | class EzyCommand { 2 | EzyCommand._(); 3 | 4 | static const ERROR = "ERROR"; 5 | static const HANDSHAKE = "HANDSHAKE"; 6 | static const PING = "PING"; 7 | static const PONG = "PONG"; 8 | static const LOGIN = "LOGIN"; 9 | static const LOGIN_ERROR = "LOGIN_ERROR"; 10 | static const LOGOUT = "LOGOUT"; 11 | static const APP_ACCESS = "APP_ACCESS"; 12 | static const APP_REQUEST = "APP_REQUEST"; 13 | static const APP_EXIT = "APP_EXIT"; 14 | static const APP_ACCESS_ERROR = "APP_ACCESS_ERROR"; 15 | static const APP_REQUEST_ERROR = "APP_REQUEST_ERROR"; 16 | static const PLUGIN_INFO = "PLUGIN_INFO"; 17 | static const PLUGIN_REQUEST = "PLUGIN_REQUEST"; 18 | } 19 | 20 | class EzyEventType { 21 | EzyEventType._(); 22 | 23 | static const CONNECTION_SUCCESS = "CONNECTION_SUCCESS"; 24 | static const CONNECTION_FAILURE = "CONNECTION_FAILURE"; 25 | static const DISCONNECTION = "DISCONNECTION"; 26 | static const LOST_PING = "LOST_PING"; 27 | static const TRY_CONNECT = "TRY_CONNECT"; 28 | } 29 | 30 | class EzyConnectionStatus { 31 | EzyConnectionStatus._(); 32 | 33 | static const NULL = "NULL"; 34 | static const CONNECTING = "CONNECTING"; 35 | static const CONNECTED = "CONNECTED"; 36 | static const DISCONNECTED = "DISCONNECTED"; 37 | static const FAILURE = "FAILURE"; 38 | static const RECONNECTING = "RECONNECTING"; 39 | } 40 | 41 | class EzyDisconnectReason { 42 | EzyDisconnectReason._(); 43 | 44 | static const CLOSE = -1; 45 | static const UNKNOWN = 0; 46 | static const IDLE = 1; 47 | static const NOT_LOGGED_IN = 2; 48 | static const ANOTHER_SESSION_LOGIN = 3; 49 | static const ADMIN_BAN = 4; 50 | static const ADMIN_KICK = 5; 51 | static const MAX_REQUEST_PER_SECOND = 6; 52 | static const MAX_REQUEST_SIZE = 7; 53 | static const SERVER_ERROR = 8; 54 | static const SERVER_NOT_RESPONDING = 400; 55 | static const UNAUTHORIZED = 401; 56 | } 57 | 58 | class EzyDisconnectReasons { 59 | static const _REASON_NAMES = { 60 | EzyDisconnectReason.CLOSE: "CLOSE", 61 | EzyDisconnectReason.UNKNOWN: "UNKNOWN", 62 | EzyDisconnectReason.IDLE: "IDLE", 63 | EzyDisconnectReason.NOT_LOGGED_IN: "NOT_LOGGED_IN", 64 | EzyDisconnectReason.ANOTHER_SESSION_LOGIN: "ANOTHER_SESSION_LOGIN", 65 | EzyDisconnectReason.ADMIN_BAN: "ADMIN_BAN", 66 | EzyDisconnectReason.ADMIN_KICK: "ADMIN_KICK", 67 | EzyDisconnectReason.MAX_REQUEST_PER_SECOND: "MAX_REQUEST_PER_SECOND", 68 | EzyDisconnectReason.MAX_REQUEST_SIZE: "MAX_REQUEST_SIZE", 69 | EzyDisconnectReason.SERVER_ERROR: "SERVER_ERROR", 70 | EzyDisconnectReason.SERVER_NOT_RESPONDING: "SERVER_NOT_RESPONDING", 71 | EzyDisconnectReason.UNAUTHORIZED: "UNAUTHORIZED" 72 | }; 73 | 74 | EzyDisconnectReasons._(); 75 | 76 | static String getDisconnectReasonName(int reasonId) { 77 | return _REASON_NAMES[reasonId] ?? reasonId.toString(); 78 | } 79 | } 80 | 81 | class EzyConnectionFailedReason { 82 | EzyConnectionFailedReason._(); 83 | 84 | static const TIMEOUT = 0; 85 | static const NETWORK_UNREACHABLE = 1; 86 | static const UNKNOWN_HOST = 2; 87 | static const CONNECTION_REFUSED = 3; 88 | static const UNKNOWN = 4; 89 | } 90 | 91 | class EzyConnectionFailedReasons { 92 | static const _REASON_NAMES = { 93 | EzyConnectionFailedReason.TIMEOUT: "TIMEOUT", 94 | EzyConnectionFailedReason.NETWORK_UNREACHABLE: "NETWORK_UNREACHABLE", 95 | EzyConnectionFailedReason.UNKNOWN_HOST: "UNKNOWN_HOST", 96 | EzyConnectionFailedReason.CONNECTION_REFUSED: "CONNECTION_REFUSED", 97 | EzyConnectionFailedReason.UNKNOWN: "UNKNOWN" 98 | }; 99 | EzyConnectionFailedReasons._(); 100 | 101 | static String getConnectionFailedReasonName(int reasonId) { 102 | return _REASON_NAMES[reasonId] ?? reasonId.toString(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/ezy_entities.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | import 'ezy_client.dart'; 4 | import 'ezy_constants.dart'; 5 | import 'ezy_handlers.dart'; 6 | import 'ezy_managers.dart'; 7 | 8 | class EzyZone { 9 | late int id; 10 | late String name; 11 | late EzyClient client; 12 | late EzyAppManager appManager; 13 | 14 | EzyZone(this.client, this.id, this.name) { 15 | appManager = EzyAppManager(name); 16 | } 17 | 18 | EzyApp? getApp() { 19 | return appManager.getApp(); 20 | } 21 | } 22 | 23 | class EzyApp { 24 | late int id; 25 | late String name; 26 | late EzyZone zone; 27 | late EzyClient client; 28 | late EzyAppDataHandlers dataHandlers; 29 | static const Map EMPTY_MAP = {}; 30 | 31 | EzyApp(this.client, this.zone, this.id, this.name) { 32 | dataHandlers = client.handlerManager.getAppDataHandlers(name); 33 | } 34 | 35 | void send(String cmd, [dynamic data = EMPTY_MAP, bool encrypted = false]) { 36 | var requestData = []; 37 | requestData.add(id); 38 | var requestParams = []; 39 | requestParams.add(cmd); 40 | requestParams.add(data); 41 | requestData.add(requestParams); 42 | client.send(EzyCommand.APP_REQUEST, requestData, encrypted); 43 | } 44 | 45 | EzyAppDataHandler? getDataHandler(String cmd) { 46 | return dataHandlers.getHandler(cmd); 47 | } 48 | } 49 | 50 | class EzyUser { 51 | late int id; 52 | late String name; 53 | 54 | EzyUser(this.id, this.name); 55 | } 56 | -------------------------------------------------------------------------------- /lib/ezy_handlers.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | import 'dart:typed_data'; 3 | 4 | import 'ezy_client.dart'; 5 | import 'ezy_constants.dart'; 6 | import 'ezy_entities.dart'; 7 | import 'ezy_logger.dart'; 8 | import 'ezy_util.dart'; 9 | import 'ezy_codec.dart'; 10 | 11 | class EzyEventHandler { 12 | void handle(Map event) {} 13 | } 14 | 15 | class EzyDataHandler { 16 | void handle(List data) {} 17 | } 18 | 19 | class EzyAbstractEventHandler extends EzyEventHandler { 20 | late EzyClient client; 21 | } 22 | 23 | class EzyAbstractDataHandler extends EzyDataHandler { 24 | late EzyClient client; 25 | } 26 | 27 | class EzyAppDataHandler { 28 | void handle(EzyApp app, T data) {} 29 | } 30 | 31 | class EzyAbstractAppDataHandler implements EzyAppDataHandler { 32 | @override 33 | void handle(EzyApp app, T data) { 34 | process(app, data); 35 | } 36 | 37 | void process(EzyApp app, T data) {} 38 | } 39 | 40 | class EzyConnectionSuccessHandler extends EzyAbstractEventHandler { 41 | var clientType = "FLUTTER"; 42 | var clientVersion = "1.0.0"; 43 | 44 | @override 45 | void handle(Map event) { 46 | sendHandshakeRequest(); 47 | postHandle(); 48 | } 49 | 50 | void postHandle() {} 51 | 52 | void sendHandshakeRequest() { 53 | generateClientKey((clientKey) => 54 | {client.send(EzyCommand.HANDSHAKE, newHandshakeRequest(clientKey))}); 55 | } 56 | 57 | List newHandshakeRequest(String? clientKey) { 58 | var clientId = getClientId(); 59 | var token = getStoredToken(); 60 | var request = []; 61 | request.add(clientId); 62 | request.add(clientKey); 63 | request.add(clientType); 64 | request.add(clientVersion); 65 | request.add(_isEnableSSL(clientKey)); 66 | request.add(token); 67 | return request; 68 | } 69 | 70 | bool _isEnableSSL(String? clientKey) { 71 | return client.enableSSL; 72 | } 73 | 74 | void _onKeyPairGenerated( 75 | EzyKeyPairProxy keyPair, Function(String?) callback) { 76 | client.privateKey = keyPair.privateKey; 77 | callback(keyPair.publicKey); 78 | } 79 | 80 | void generateClientKey(Function(String?) callback) { 81 | if (client.enableSSL) { 82 | EzyRSAProxy.getInstance().generateKeyPair( 83 | (keyPair) => {_onKeyPairGenerated(keyPair, callback)}); 84 | } else { 85 | callback(null); 86 | } 87 | } 88 | 89 | String getClientId() { 90 | return UUID.random(); 91 | } 92 | 93 | String getStoredToken() { 94 | return ""; 95 | } 96 | } 97 | 98 | //======================================================= 99 | class EzyConnectionFailureHandler extends EzyAbstractEventHandler { 100 | @override 101 | void handle(Map event) { 102 | var reason = event["reason"] as int; 103 | var reasonName = 104 | EzyConnectionFailedReasons.getConnectionFailedReasonName(reason); 105 | EzyLogger.warn("connection failure, reason = $reasonName"); 106 | var config = client.config; 107 | var reconnectConfig = config.reconnect; 108 | var should = shouldReconnect(event); 109 | var reconnectEnable = reconnectConfig.enable; 110 | var mustReconnect = reconnectEnable && should; 111 | client.setStatus(EzyConnectionStatus.FAILURE); 112 | if (mustReconnect) { 113 | client.reconnect().then((value) => {_onReconnect(event, value)}); 114 | } else { 115 | onConnectionFailed(event); 116 | postHandle(event); 117 | } 118 | } 119 | 120 | bool shouldReconnect(Map event) { 121 | return true; 122 | } 123 | 124 | void _onReconnect(Map event, bool success) { 125 | if (success) { 126 | onReconnecting(event); 127 | } else { 128 | onConnectionFailed(event); 129 | } 130 | postHandle(event); 131 | } 132 | 133 | void onReconnecting(Map event) {} 134 | 135 | void onConnectionFailed(Map event) {} 136 | 137 | void postHandle(Map event) {} 138 | } 139 | 140 | //======================================================= 141 | class EzyDisconnectionHandler extends EzyAbstractEventHandler { 142 | @override 143 | void handle(Map event) { 144 | var reason = event["reason"] as int; 145 | var reasonName = EzyDisconnectReasons.getDisconnectReasonName(reason); 146 | EzyLogger.info("handle disconnection, reason = $reasonName"); 147 | preHandle(event); 148 | var config = client.config; 149 | var reconnectConfig = config.reconnect; 150 | var should = shouldReconnect(event); 151 | var reconnectEnable = reconnectConfig.enable; 152 | var mustReconnect = reconnectEnable && 153 | reason != EzyDisconnectReason.UNAUTHORIZED && 154 | reason != EzyDisconnectReason.CLOSE && 155 | should; 156 | client.setStatus(EzyConnectionStatus.DISCONNECTED); 157 | if (mustReconnect) { 158 | client.reconnect().then((value) => {_onReconnect(event, value)}); 159 | } else { 160 | onDisconnected(event); 161 | postHandle(event); 162 | } 163 | } 164 | 165 | void _onReconnect(Map event, bool success) { 166 | if (success) { 167 | onReconnecting(event); 168 | } else { 169 | onDisconnected(event); 170 | } 171 | postHandle(event); 172 | } 173 | 174 | void preHandle(Map event) {} 175 | 176 | bool shouldReconnect(Map event) { 177 | var reason = event["reason"] as int; 178 | if (reason == EzyDisconnectReason.ANOTHER_SESSION_LOGIN) { 179 | return false; 180 | } 181 | return true; 182 | } 183 | 184 | void control(Map event) {} 185 | 186 | void onReconnecting(Map event) {} 187 | 188 | void onDisconnected(Map event) {} 189 | 190 | void postHandle(Map event) {} 191 | } 192 | 193 | //======================================================= 194 | class EzyPongHandler extends EzyAbstractDataHandler {} 195 | 196 | //======================================================= 197 | 198 | class EzyHandshakeHandler extends EzyAbstractDataHandler { 199 | @override 200 | void handle(List data) { 201 | startPing(); 202 | doHandle(data); 203 | } 204 | 205 | void _onSessionKeyDecrypted(List data, Uint8List? sessionKey, bool success) { 206 | if (sessionKey != null) { 207 | client.setSessionKey(sessionKey); 208 | } 209 | if (success) { 210 | handleLogin(); 211 | } 212 | postHandle(data); 213 | } 214 | 215 | void doHandle(List data) { 216 | client.sessionToken = data[1] as String; 217 | client.sessionId = data[2] as int; 218 | if (client.enableSSL) { 219 | decryptSessionKey( 220 | data[3], 221 | (sessionKey, success) => 222 | {_onSessionKeyDecrypted(data, sessionKey, success)}); 223 | } else { 224 | _onSessionKeyDecrypted(data, null, true); 225 | } 226 | } 227 | 228 | void decryptSessionKey( 229 | Uint8List? encryptedSessionKey, Function(Uint8List?, bool) callback) { 230 | if (encryptedSessionKey == null) { 231 | if (client.enableDebug) { 232 | callback(null, true); 233 | return; 234 | } 235 | EzyLogger.error( 236 | "maybe server was not enable SSL, you must enable SSL on server or disable SSL on your client or enable debug mode", 237 | ); 238 | client.close(); 239 | callback(null, false); 240 | return; 241 | } 242 | EzyRSAProxy.getInstance().decrypt(encryptedSessionKey, client.privateKey!, 243 | (sessionKey) => {callback(sessionKey, true)}); 244 | } 245 | 246 | void postHandle(List data) {} 247 | 248 | void handleLogin() { 249 | var loginRequest = getLoginRequest(); 250 | client.send(EzyCommand.LOGIN, loginRequest, encryptedLoginRequest()); 251 | } 252 | 253 | bool encryptedLoginRequest() { 254 | return false; 255 | } 256 | 257 | List getLoginRequest() { 258 | var array = []; 259 | array.add("test"); 260 | array.add("test"); 261 | array.add("test"); 262 | array.add([]); 263 | return array; 264 | } 265 | 266 | void startPing() { 267 | client.startPingSchedule(); 268 | } 269 | } 270 | 271 | //======================================================= 272 | class EzyLoginSuccessHandler extends EzyAbstractDataHandler { 273 | @override 274 | void handle(List data) { 275 | var responseData = data[4]; 276 | var user = newUser(data); 277 | var zone = newZone(data); 278 | client.me = user; 279 | client.zone = zone; 280 | handleLoginSuccess(responseData); 281 | EzyLogger.info("user: ${user.name} logged in successfully"); 282 | } 283 | 284 | EzyUser newUser(List data) { 285 | var userId = data[2] as int; 286 | var username = data[3] as String; 287 | var user = EzyUser(userId, username); 288 | return user; 289 | } 290 | 291 | EzyZone newZone(List data) { 292 | var zoneId = data[0] as int; 293 | var zoneName = data[1] as String; 294 | var zone = EzyZone(client, zoneId, zoneName); 295 | return zone; 296 | } 297 | 298 | void handleLoginSuccess(dynamic responseData) {} 299 | } 300 | 301 | //======================================================= 302 | class EzyLoginErrorHandler extends EzyAbstractDataHandler { 303 | @override 304 | void handle(List data) { 305 | client.disconnect(EzyDisconnectReason.UNAUTHORIZED); 306 | handleLoginError(data); 307 | } 308 | 309 | void handleLoginError(List data) {} 310 | } 311 | 312 | //======================================================= 313 | class EzyAppAccessHandler extends EzyAbstractDataHandler { 314 | @override 315 | void handle(List data) { 316 | var zone = client.zone; 317 | var appManager = zone!.appManager; 318 | var app = newApp(zone, data); 319 | appManager.addApp(app); 320 | postHandle(app, data); 321 | EzyLogger.info("access app: ${app.name} successfully"); 322 | } 323 | 324 | EzyApp newApp(EzyZone zone, List data) { 325 | var appId = data[0] as int; 326 | var appName = data[1] as String; 327 | var app = EzyApp(client, zone, appId, appName); 328 | return app; 329 | } 330 | 331 | void postHandle(EzyApp app, List data) {} 332 | } 333 | 334 | //======================================================= 335 | class EzyAppExitHandler extends EzyAbstractDataHandler { 336 | @override 337 | void handle(List data) { 338 | var zone = client.zone; 339 | var appManager = zone!.appManager; 340 | var appId = data[0] as int; 341 | var reasonId = data[1] as int; 342 | var app = appManager.removeApp(appId); 343 | if (app != null) { 344 | postHandle(app, data); 345 | EzyLogger.info("user exit app: ${app.name}, reason: $reasonId"); 346 | } 347 | } 348 | 349 | void postHandle(EzyApp app, List data) {} 350 | } 351 | 352 | //======================================================= 353 | class EzyAppResponseHandler extends EzyAbstractDataHandler { 354 | @override 355 | void handle(List data) { 356 | var appId = data[0] as int; 357 | var responseData = data[1] as List; 358 | var cmd = responseData[0]; 359 | var commandData = responseData[1]; 360 | 361 | var app = client.getAppById(appId); 362 | if (app == null) { 363 | EzyLogger.info("receive message when has not joined app yet"); 364 | return; 365 | } 366 | var handler = app.getDataHandler(cmd); 367 | if (handler != null) { 368 | handler.handle(app, commandData); 369 | } else { 370 | EzyLogger.warn("app: ${app.name} has no handler for command: $cmd"); 371 | } 372 | } 373 | } 374 | 375 | //======================================================= 376 | class EzyEventHandlers { 377 | late EzyClient client; 378 | late Map handlers; 379 | 380 | EzyEventHandlers(this.client) { 381 | handlers = Map(); 382 | } 383 | 384 | void addHandler(String eventType, EzyEventHandler handler) { 385 | var abs = handler as EzyAbstractEventHandler; 386 | abs.client = client; 387 | handlers[eventType] = handler; 388 | } 389 | 390 | EzyEventHandler? getHandler(String eventType) { 391 | return handlers[eventType]; 392 | } 393 | 394 | void handle(String eventType, Map data) { 395 | var handler = getHandler(eventType); 396 | if (handler != null) { 397 | handler.handle(data); 398 | } else { 399 | EzyLogger.warn("has no handler with event: $eventType"); 400 | } 401 | } 402 | } 403 | 404 | //======================================================= 405 | 406 | class EzyDataHandlers { 407 | late EzyClient client; 408 | late Map handlerByCommand; 409 | 410 | EzyDataHandlers(this.client) { 411 | handlerByCommand = Map(); 412 | } 413 | 414 | void addHandler(String cmd, EzyDataHandler handler) { 415 | var abs = handler as EzyAbstractDataHandler; 416 | abs.client = client; 417 | handlerByCommand[cmd] = handler; 418 | } 419 | 420 | EzyDataHandler? getHandler(String cmd) { 421 | return handlerByCommand[cmd]; 422 | } 423 | 424 | void handle(String cmd, dynamic data) { 425 | var handler = getHandler(cmd); 426 | if (handler != null) { 427 | handler.handle(data); 428 | } else { 429 | EzyLogger.warn("has no handler with command: $cmd"); 430 | } 431 | } 432 | } 433 | 434 | //======================================================= 435 | 436 | class EzyAppDataHandlers { 437 | late Map _handlerByAppName; 438 | 439 | EzyAppDataHandlers() { 440 | _handlerByAppName = Map(); 441 | } 442 | 443 | void addHandler(String cmd, EzyAppDataHandler handler) { 444 | _handlerByAppName[cmd] = handler; 445 | } 446 | 447 | EzyAppDataHandler? getHandler(String cmd) { 448 | return _handlerByAppName[cmd]; 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /lib/ezy_logger.dart: -------------------------------------------------------------------------------- 1 | import 'ezy_proxy.dart'; 2 | 3 | class EzyLogger { 4 | EzyLogger._(); 5 | 6 | static void error(String message) { 7 | Map params = { 8 | "level": "e", 9 | "message": message 10 | }; 11 | EzyProxy.run("log", params); 12 | } 13 | 14 | static void warn(String message) { 15 | Map params = { 16 | "level": "w", 17 | "message": message 18 | }; 19 | EzyProxy.run("log", params); 20 | } 21 | 22 | static void info(String message) { 23 | Map params = { 24 | "level": "i", 25 | "message": message 26 | }; 27 | EzyProxy.run("log", params); 28 | } 29 | } -------------------------------------------------------------------------------- /lib/ezy_managers.dart: -------------------------------------------------------------------------------- 1 | import 'ezy_client.dart'; 2 | import 'ezy_constants.dart'; 3 | import 'ezy_entities.dart'; 4 | import 'ezy_handlers.dart'; 5 | import 'ezy_logger.dart'; 6 | 7 | class EzyAppManager { 8 | late String zoneName; 9 | late List appList; 10 | late Map appById; 11 | late Map appByName; 12 | 13 | EzyAppManager(this.zoneName) { 14 | appList = []; 15 | appById = Map(); 16 | appByName = Map(); 17 | } 18 | 19 | EzyApp? getApp() { 20 | if (appList.isEmpty) { 21 | EzyLogger.warn("there is no app in zone: $zoneName"); 22 | return null; 23 | } 24 | return appList[0]; 25 | } 26 | 27 | void addApp(EzyApp app) { 28 | appList.add(app); 29 | appById[app.id] = app; 30 | appByName[app.name] = app; 31 | } 32 | 33 | EzyApp? removeApp(int appId) { 34 | var app = appById[appId]; 35 | if (app != null) { 36 | appList.remove(app); 37 | appById.remove(app.id); 38 | appByName.remove(app.name); 39 | } 40 | return app; 41 | } 42 | 43 | EzyApp? getAppById(int appId) { 44 | return appById[appId]; 45 | } 46 | 47 | EzyApp? getAppByName(String appName) { 48 | return appByName[appName]; 49 | } 50 | } 51 | 52 | //=================================================== 53 | class EzyHandlerManager { 54 | late EzyClient client; 55 | late EzyDataHandlers dataHandlers; 56 | late EzyEventHandlers eventHandlers; 57 | late Map appDataHandlersByAppName; 58 | 59 | EzyHandlerManager(this.client) { 60 | appDataHandlersByAppName = Map(); 61 | dataHandlers = _newDataHandlers(); 62 | eventHandlers = _newEventHandlers(); 63 | } 64 | 65 | static EzyHandlerManager create(EzyClient client) { 66 | var pRet = EzyHandlerManager(client); 67 | return pRet; 68 | } 69 | 70 | EzyEventHandlers _newEventHandlers() { 71 | var handlers = EzyEventHandlers(client); 72 | handlers.addHandler( 73 | EzyEventType.CONNECTION_SUCCESS, EzyConnectionSuccessHandler()); 74 | handlers.addHandler( 75 | EzyEventType.CONNECTION_FAILURE, EzyConnectionFailureHandler()); 76 | handlers.addHandler(EzyEventType.DISCONNECTION, EzyDisconnectionHandler()); 77 | return handlers; 78 | } 79 | 80 | EzyDataHandlers _newDataHandlers() { 81 | var handlers = EzyDataHandlers(client); 82 | handlers.addHandler(EzyCommand.PONG, EzyPongHandler()); 83 | handlers.addHandler(EzyCommand.HANDSHAKE, EzyHandshakeHandler()); 84 | handlers.addHandler(EzyCommand.LOGIN, EzyLoginSuccessHandler()); 85 | handlers.addHandler(EzyCommand.LOGIN_ERROR, EzyLoginErrorHandler()); 86 | handlers.addHandler(EzyCommand.APP_ACCESS, EzyAppAccessHandler()); 87 | handlers.addHandler(EzyCommand.APP_EXIT, EzyAppExitHandler()); 88 | handlers.addHandler(EzyCommand.APP_REQUEST, EzyAppResponseHandler()); 89 | return handlers; 90 | } 91 | 92 | EzyDataHandler? getDataHandler(String cmd) { 93 | return dataHandlers.getHandler(cmd); 94 | } 95 | 96 | EzyEventHandler? getEventHandler(String eventType) { 97 | return eventHandlers.getHandler(eventType); 98 | } 99 | 100 | EzyAppDataHandlers getAppDataHandlers(String appName) { 101 | var answer = appDataHandlersByAppName[appName]; 102 | if (answer == null) { 103 | answer = EzyAppDataHandlers(); 104 | appDataHandlersByAppName[appName] = answer; 105 | } 106 | return answer; 107 | } 108 | 109 | void addDataHandler(String cmd, EzyDataHandler handler) { 110 | dataHandlers.addHandler(cmd, handler); 111 | } 112 | 113 | void addEventHandler(String eventType, EzyEventHandler handler) { 114 | eventHandlers.addHandler(eventType, handler); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/ezy_proxy.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'ezy_clients.dart'; 3 | import 'ezy_logger.dart'; 4 | import 'ezy_client.dart'; 5 | 6 | class EzyProxy { 7 | late MethodChannel _methodChannel; 8 | 9 | static final EzyProxy _INSTANCE = EzyProxy._(); 10 | 11 | EzyProxy._() { 12 | _methodChannel = const MethodChannel('com.tvd12.ezyfoxserver.client'); 13 | _methodChannel.setMethodCallHandler(_handleSocketEventDatas); 14 | } 15 | 16 | static EzyProxy getInstance() { 17 | return _INSTANCE; 18 | } 19 | 20 | Future _handleSocketEventDatas(MethodCall call) async { 21 | // type inference will work here avoiding an explicit cast 22 | switch (call.method) { 23 | case "ezy.event": 24 | _onSocketEvent(call.arguments); 25 | break; 26 | case "ezy.data": 27 | _onSocketData(call.arguments); 28 | break; 29 | default: 30 | EzyLogger.warn( 31 | "there is no handler for method: ${call.method}, ignore it", 32 | ); 33 | } 34 | } 35 | 36 | void _onSocketEvent(Map arguments) { 37 | String clientName = arguments["clientName"]; 38 | String eventType = arguments["eventType"]; 39 | dynamic data = arguments["data"]; 40 | EzyClient client = _getClient(clientName); 41 | client.handleEvent(eventType, data); 42 | } 43 | 44 | void _onSocketData(Map arguments) { 45 | String clientName = arguments["clientName"]; 46 | String command = arguments["command"]; 47 | dynamic data = arguments["data"]; 48 | EzyClient client = _getClient(clientName); 49 | client.handleData(command, data); 50 | } 51 | 52 | static Future run(String method, Map params) { 53 | return EzyProxy.getInstance()._methodChannel.invokeMethod(method, params); 54 | } 55 | 56 | EzyClient _getClient(String clientName) { 57 | return EzyClients.getInstance().getClient(clientName); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/ezy_setup.dart: -------------------------------------------------------------------------------- 1 | import 'ezy_handlers.dart'; 2 | import 'ezy_managers.dart'; 3 | 4 | class EzySetup { 5 | late EzyHandlerManager handlerManager; 6 | late Map appSetupByAppName; 7 | 8 | EzySetup(this.handlerManager) { 9 | appSetupByAppName = Map(); 10 | } 11 | 12 | EzySetup addDataHandler(String cmd, EzyDataHandler handler) { 13 | handlerManager.addDataHandler(cmd, handler); 14 | return this; 15 | } 16 | 17 | EzySetup addEventHandler(String eventType, EzyEventHandler handler) { 18 | handlerManager.addEventHandler(eventType, handler); 19 | return this; 20 | } 21 | 22 | EzyAppSetup setupApp(String appName) { 23 | var appSetup = appSetupByAppName[appName]; 24 | if (appSetup == null) { 25 | var appDataHandlers = handlerManager.getAppDataHandlers(appName); 26 | appSetup = EzyAppSetup(appDataHandlers, this); 27 | appSetupByAppName[appName] = appSetup; 28 | } 29 | return appSetup; 30 | } 31 | } 32 | 33 | class EzyAppSetup { 34 | late EzySetup parent; 35 | late EzyAppDataHandlers dataHandlers; 36 | 37 | EzyAppSetup(this.dataHandlers, this.parent); 38 | 39 | EzyAppSetup addDataHandler(String cmd, EzyAppDataHandler handler) { 40 | dataHandlers.addHandler(cmd, handler); 41 | return this; 42 | } 43 | 44 | EzySetup done() { 45 | return parent; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/ezy_util.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | class UUID { 4 | static const _CHARS = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; 5 | UUID._(){} 6 | 7 | static String random() { 8 | return "${_randomString(8)}-${_randomString(8)}-${_randomString(8)}-${_randomString(8)}"; 9 | } 10 | 11 | static String _randomString(int length) { 12 | Random random = Random(); 13 | return String.fromCharCodes( 14 | Iterable.generate( 15 | length, (_) => _CHARS.codeUnitAt(random.nextInt(_CHARS.length)) 16 | ) 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ezyfox_server_flutter_client 2 | description: EzyFox Server's Flutter client sdk. 3 | version: 0.0.1 4 | homepage: 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | flutter: ">=1.20.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter 17 | flutter_lints: ^1.0.0 18 | 19 | # For information on the generic Dart part of this file, see the 20 | # following page: https://dart.dev/tools/pub/pubspec 21 | 22 | # The following section is specific to Flutter. 23 | flutter: 24 | # This section identifies this Flutter project as a plugin project. 25 | # The 'pluginClass' and Android 'package' identifiers should not ordinarily 26 | # be modified. They are used by the tooling to maintain consistency when 27 | # adding or updating assets for this project. 28 | plugin: 29 | platforms: 30 | android: 31 | package: com.tvd12.ezyfoxserver.client.flutter 32 | pluginClass: EzyFlutterClientPlugin 33 | 34 | # To add assets to your plugin package, add an assets section, like this: 35 | # assets: 36 | # - images/a_dot_burr.jpeg 37 | # - images/a_dot_ham.jpeg 38 | # 39 | # For details regarding assets in packages, see 40 | # https://flutter.dev/assets-and-images/#from-packages 41 | # 42 | # An image asset can refer to one or more resolution-specific "variants", see 43 | # https://flutter.dev/assets-and-images/#resolution-aware. 44 | 45 | # To add custom fonts to your plugin package, 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 in packages, see 63 | # https://flutter.dev/custom-fonts/#from-packages 64 | -------------------------------------------------------------------------------- /test/ezyfox_server_flutter_client_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | void main() { 5 | const MethodChannel channel = MethodChannel('ezyfox_server_flutter_client'); 6 | 7 | TestWidgetsFlutterBinding.ensureInitialized(); 8 | 9 | setUp(() { 10 | channel.setMockMethodCallHandler((MethodCall methodCall) async { 11 | return '42'; 12 | }); 13 | }); 14 | 15 | tearDown(() { 16 | channel.setMockMethodCallHandler(null); 17 | }); 18 | } 19 | --------------------------------------------------------------------------------