├── src └── androidProj │ ├── settings.gradle │ ├── .idea │ ├── copyright │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── codeStyles │ │ ├── codeStyleConfig.xml │ │ └── Project.xml │ ├── runConfigurations.xml │ ├── compiler.xml │ ├── misc.xml │ └── codeStyleSettings.xml │ ├── nativeeditplugin │ ├── src │ │ └── main │ │ │ ├── res │ │ │ └── values │ │ │ │ └── strings.xml │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── com │ │ │ └── bkmin │ │ │ └── android │ │ │ ├── NativeEditPlugin.java │ │ │ └── EditBox.java │ ├── libs │ │ └── UnityPlayer.jar │ ├── proguard-rules.pro │ └── build.gradle │ ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── build.gradle │ ├── gradle.properties │ ├── .gitignore │ ├── gradlew.bat │ └── gradlew ├── demo ├── Assets │ ├── NativeEditPlugin │ │ ├── demo │ │ ├── Plugins │ │ ├── scripts │ │ ├── demo.meta │ │ ├── Plugins.meta │ │ └── scripts.meta │ ├── NativeEditPlugin.meta │ ├── Plugins.meta │ └── Plugins │ │ └── Editor.meta ├── ProjectSettings │ ├── ProjectVersion.txt │ ├── ClusterInputManager.asset │ ├── NetworkManager.asset │ ├── TimeManager.asset │ ├── EditorBuildSettings.asset │ ├── AudioManager.asset │ ├── TagManager.asset │ ├── DynamicsManager.asset │ ├── EditorSettings.asset │ ├── UnityConnectSettings.asset │ ├── Physics2DSettings.asset │ ├── NavMeshAreas.asset │ ├── GraphicsSettings.asset │ ├── QualitySettings.asset │ ├── InputManager.asset │ └── ProjectSettings.asset ├── UnityPackageManager │ └── manifest.json └── .gitignore ├── release └── NativeEditPlugin │ ├── scripts │ ├── NativeEdit.asmdef │ ├── NativeEdit.asmdef.meta │ ├── JsonObject.cs.meta │ ├── MiniJSON.cs.meta │ ├── NativeEditBox.cs.meta │ ├── PluginMsgHandler.cs.meta │ ├── PluginMsgReceiver.cs.meta │ ├── PluginMsgReceiver.cs │ ├── JsonObject.cs │ ├── PluginMsgHandler.cs │ ├── NativeEditBox.cs │ └── MiniJSON.cs │ ├── Plugins │ ├── Android │ │ ├── nativeeditplugin-release.aar │ │ ├── AndroidManifest.xml.meta │ │ ├── nativeeditplugin-release.aar.meta │ │ └── AndroidManifest.xml │ ├── iOS.meta │ ├── Android.meta │ └── iOS │ │ ├── PlaceholderTextView.h │ │ ├── EditBox_iOS.h.meta │ │ ├── JsonObject.h.meta │ │ ├── PlaceholderTextView.h.meta │ │ ├── EditBox_iOS.m.meta │ │ ├── JsonObject.m.meta │ │ ├── PlaceholderTextView.m.meta │ │ ├── PluginMsgInterface.mm.meta │ │ ├── JsonObject.h │ │ ├── EditBox_iOS.h │ │ ├── PluginMsgInterface.mm │ │ ├── PlaceholderTextView.m │ │ ├── JsonObject.m │ │ └── EditBox_iOS.m │ └── demo │ ├── demo.unity.meta │ ├── DemoLog.cs.meta │ └── DemoLog.cs ├── .gitignore └── README.md /src/androidProj/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':nativeeditplugin' 2 | -------------------------------------------------------------------------------- /demo/Assets/NativeEditPlugin/demo: -------------------------------------------------------------------------------- 1 | ../../../release/NativeEditPlugin/demo/ -------------------------------------------------------------------------------- /demo/ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2017.4.3f1 2 | -------------------------------------------------------------------------------- /demo/Assets/NativeEditPlugin/Plugins: -------------------------------------------------------------------------------- 1 | ../../../release/NativeEditPlugin/Plugins/ -------------------------------------------------------------------------------- /demo/Assets/NativeEditPlugin/scripts: -------------------------------------------------------------------------------- 1 | ../../../release/NativeEditPlugin/scripts/ -------------------------------------------------------------------------------- /demo/UnityPackageManager/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | } 4 | } 5 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/NativeEdit.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NativeEdit" 3 | } 4 | -------------------------------------------------------------------------------- /src/androidProj/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS generated files 2 | .DS_Store 3 | .DS_Store? 4 | ._* 5 | .Spotlight-V100 6 | .Trashes 7 | Icon? 8 | ehthumbs.db 9 | Thumbs.db 10 | -------------------------------------------------------------------------------- /src/androidProj/nativeeditplugin/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | nativeeditplugin 3 | 4 | -------------------------------------------------------------------------------- /src/androidProj/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiansuixin/UnityNativeEdit/HEAD/src/androidProj/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/androidProj/nativeeditplugin/libs/UnityPlayer.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiansuixin/UnityNativeEdit/HEAD/src/androidProj/nativeeditplugin/libs/UnityPlayer.jar -------------------------------------------------------------------------------- /src/androidProj/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/Android/nativeeditplugin-release.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiansuixin/UnityNativeEdit/HEAD/release/NativeEditPlugin/Plugins/Android/nativeeditplugin-release.aar -------------------------------------------------------------------------------- /src/androidProj/.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /demo/ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!149 &1 4 | NetworkManager: 5 | m_ObjectHideFlags: 0 6 | m_DebugLevel: 0 7 | m_Sendrate: 15 8 | m_AssetToPrefab: {} 9 | -------------------------------------------------------------------------------- /demo/ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | -------------------------------------------------------------------------------- /demo/Assets/NativeEditPlugin.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d541cfba5912d43fc837495d4a0d6011 3 | folderAsset: yes 4 | timeCreated: 1430959055 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/demo/demo.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 015099fa862476741b43b0885edbc8dc 3 | timeCreated: 1562335729 4 | licenseType: Free 5 | DefaultImporter: 6 | externalObjects: {} 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /demo/Assets/Plugins.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 943802327f2d0104f859142c6616a6a6 3 | folderAsset: yes 4 | timeCreated: 1562335845 5 | licenseType: Free 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /demo/ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: 8 | - enabled: 1 9 | path: Assets/NativeEditPlugin/demo/demo.unity 10 | -------------------------------------------------------------------------------- /demo/Assets/Plugins/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 571b27321657f4e44899a901becd95b6 3 | folderAsset: yes 4 | timeCreated: 1562335845 5 | licenseType: Free 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /demo/Assets/NativeEditPlugin/demo.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aa150935e45ac9f4b952cbb0eee0b4ba 3 | folderAsset: yes 4 | timeCreated: 1562335729 5 | licenseType: Free 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /src/androidProj/nativeeditplugin/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /demo/Assets/NativeEditPlugin/Plugins.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 90b94ef238015574bb5caa9110099943 3 | folderAsset: yes 4 | timeCreated: 1562335729 5 | licenseType: Free 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /demo/Assets/NativeEditPlugin/scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c6a7b1506de0c9d4ab8dc0cb699cd473 3 | folderAsset: yes 4 | timeCreated: 1562335729 5 | licenseType: Free 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0a154f58978011a49994efe0447d5f20 3 | folderAsset: yes 4 | timeCreated: 1562335729 5 | licenseType: Free 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/Android.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c775b6d53a8dec14a8fca5610b7fa175 3 | folderAsset: yes 4 | timeCreated: 1562335729 5 | licenseType: Free 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/Android/AndroidManifest.xml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 178feb45fbc0ffc44b3b6c35584d937b 3 | timeCreated: 1562335736 4 | licenseType: Free 5 | TextScriptImporter: 6 | externalObjects: {} 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/NativeEdit.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5048c5d624437e84e903c27d5fccfd54 3 | timeCreated: 1562335732 4 | licenseType: Free 5 | AssemblyDefinitionImporter: 6 | externalObjects: {} 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/androidProj/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jun 20 12:24:46 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip 7 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/demo/DemoLog.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dd3dfc3c19b13d14db4ba733414bad39 3 | timeCreated: 1562581494 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/JsonObject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e7b7b423dde343459ac6dca00929ef1 3 | timeCreated: 1562335732 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/MiniJSON.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6cd310c07c266294b8edbe9d1fe19e22 3 | timeCreated: 1562335732 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/NativeEditBox.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ca4cf2df1cca4e845bbdecbf0e89ee48 3 | timeCreated: 1562335732 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/PluginMsgHandler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b9c8f233db7d1dc42a62abcca68d41a3 3 | timeCreated: 1562335732 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/PluginMsgReceiver.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f36a2a0b94a176c42abb38a80d45f694 3 | timeCreated: 1562335732 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /demo/ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | m_Volume: 1 7 | Rolloff Scale: 1 8 | Doppler Factor: 1 9 | Default Speaker Mode: 2 10 | m_SampleRate: 0 11 | m_DSPBufferSize: 0 12 | m_VirtualVoiceCount: 512 13 | m_RealVoiceCount: 32 14 | m_SpatializerPlugin: 15 | m_DisableAudio: 0 16 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/PlaceholderTextView.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @interface PlaceholderTextView : UITextView 5 | { 6 | NSObject* _editBox; 7 | } 8 | 9 | @property(nonatomic, strong) NSString *placeholder; 10 | 11 | @property (nonatomic, strong) UIColor *realTextColor UI_APPEARANCE_SELECTOR; 12 | @property (nonatomic, strong) UIColor *placeholderColor UI_APPEARANCE_SELECTOR; 13 | 14 | -(void) SetEditbox:(NSObject*) box; 15 | 16 | @end -------------------------------------------------------------------------------- /src/androidProj/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.4.1' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | google() 19 | jcenter() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /demo/ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /src/androidProj/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/EditBox_iOS.h.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7ba18c4df533b69489cede94c2801593 3 | timeCreated: 1562335736 4 | licenseType: Free 5 | PluginImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | iconMap: {} 9 | executionOrder: {} 10 | isPreloaded: 0 11 | isOverridable: 0 12 | platformData: 13 | - first: 14 | Any: 15 | second: 16 | enabled: 1 17 | settings: {} 18 | - first: 19 | Editor: Editor 20 | second: 21 | enabled: 0 22 | settings: 23 | DefaultValueInitialized: true 24 | userData: 25 | assetBundleName: 26 | assetBundleVariant: 27 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/JsonObject.h.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c17de6c72041dc74ea5a3e1544358419 3 | timeCreated: 1562335736 4 | licenseType: Free 5 | PluginImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | iconMap: {} 9 | executionOrder: {} 10 | isPreloaded: 0 11 | isOverridable: 0 12 | platformData: 13 | - first: 14 | Any: 15 | second: 16 | enabled: 1 17 | settings: {} 18 | - first: 19 | Editor: Editor 20 | second: 21 | enabled: 0 22 | settings: 23 | DefaultValueInitialized: true 24 | userData: 25 | assetBundleName: 26 | assetBundleVariant: 27 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/PlaceholderTextView.h.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff17a4f0899f1c044b374ebc76e9642a 3 | timeCreated: 1562335736 4 | licenseType: Free 5 | PluginImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | iconMap: {} 9 | executionOrder: {} 10 | isPreloaded: 0 11 | isOverridable: 0 12 | platformData: 13 | - first: 14 | Any: 15 | second: 16 | enabled: 1 17 | settings: {} 18 | - first: 19 | Editor: Editor 20 | second: 21 | enabled: 0 22 | settings: 23 | DefaultValueInitialized: true 24 | userData: 25 | assetBundleName: 26 | assetBundleVariant: 27 | -------------------------------------------------------------------------------- /demo/ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_SolverIterationCount: 6 13 | m_QueriesHitTriggers: 1 14 | m_EnableAdaptiveForce: 0 15 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 16 | -------------------------------------------------------------------------------- /demo/ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 7 7 | m_ExternalVersionControlSupport: Visible Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 1 10 | m_DefaultBehaviorMode: 1 11 | m_SpritePackerMode: 2 12 | m_SpritePackerPaddingPower: 1 13 | m_EtcTextureCompressorBehavior: 0 14 | m_EtcTextureFastCompressor: 2 15 | m_EtcTextureNormalCompressor: 2 16 | m_EtcTextureBestCompressor: 5 17 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef 18 | m_ProjectGenerationRootNamespace: 19 | m_UserGeneratedProjectSuffix: 20 | m_CollabEditorSettings: 21 | inProgressEnabled: 1 22 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/Android/nativeeditplugin-release.aar.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0cba3a7ec52957948905b705a410cde1 3 | timeCreated: 1562335736 4 | licenseType: Free 5 | PluginImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | iconMap: {} 9 | executionOrder: {} 10 | isPreloaded: 0 11 | isOverridable: 0 12 | platformData: 13 | - first: 14 | Android: Android 15 | second: 16 | enabled: 1 17 | settings: {} 18 | - first: 19 | Any: 20 | second: 21 | enabled: 0 22 | settings: {} 23 | - first: 24 | Editor: Editor 25 | second: 26 | enabled: 0 27 | settings: 28 | DefaultValueInitialized: true 29 | userData: 30 | assetBundleName: 31 | assetBundleVariant: 32 | -------------------------------------------------------------------------------- /src/androidProj/nativeeditplugin/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/kyungminbang/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /src/androidProj/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/demo/DemoLog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using UnityEngine.UI; 4 | 5 | public class DemoLog : MonoBehaviour 6 | { 7 | private Text txt; 8 | 9 | private void Start() 10 | { 11 | txt = GetComponent(); 12 | } 13 | 14 | public void OnEditValueChanged(string str) 15 | { 16 | txt.text = $"val changed: {str}"; 17 | } 18 | 19 | public void OnEndEdit(string str) 20 | { 21 | txt.text = $"edit ended: {str}"; 22 | } 23 | 24 | public void OnReturnPressed(NativeEditBox editBox) 25 | { 26 | //hide keyboard 27 | editBox.SetFocus(false); 28 | txt.text = "return pressed"; 29 | } 30 | 31 | public void OnBeginEdit(NativeEditBox editBox) 32 | { 33 | txt.text = "begin editing"; 34 | } 35 | } -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/EditBox_iOS.m.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f3c967df2137e6f4e8a082dbb10c37d5 3 | timeCreated: 1562335736 4 | licenseType: Free 5 | PluginImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | iconMap: {} 9 | executionOrder: {} 10 | isPreloaded: 0 11 | isOverridable: 0 12 | platformData: 13 | - first: 14 | Any: 15 | second: 16 | enabled: 0 17 | settings: {} 18 | - first: 19 | Editor: Editor 20 | second: 21 | enabled: 0 22 | settings: 23 | DefaultValueInitialized: true 24 | - first: 25 | iPhone: iOS 26 | second: 27 | enabled: 1 28 | settings: {} 29 | - first: 30 | tvOS: tvOS 31 | second: 32 | enabled: 1 33 | settings: {} 34 | userData: 35 | assetBundleName: 36 | assetBundleVariant: 37 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/JsonObject.m.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a506d459e8a7bdb40919f1c6deba056e 3 | timeCreated: 1562335736 4 | licenseType: Free 5 | PluginImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | iconMap: {} 9 | executionOrder: {} 10 | isPreloaded: 0 11 | isOverridable: 0 12 | platformData: 13 | - first: 14 | Any: 15 | second: 16 | enabled: 0 17 | settings: {} 18 | - first: 19 | Editor: Editor 20 | second: 21 | enabled: 0 22 | settings: 23 | DefaultValueInitialized: true 24 | - first: 25 | iPhone: iOS 26 | second: 27 | enabled: 1 28 | settings: {} 29 | - first: 30 | tvOS: tvOS 31 | second: 32 | enabled: 1 33 | settings: {} 34 | userData: 35 | assetBundleName: 36 | assetBundleVariant: 37 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/PlaceholderTextView.m.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7ee1933a0b6b3474ebab2365a5b6c7a3 3 | timeCreated: 1562335736 4 | licenseType: Free 5 | PluginImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | iconMap: {} 9 | executionOrder: {} 10 | isPreloaded: 0 11 | isOverridable: 0 12 | platformData: 13 | - first: 14 | Any: 15 | second: 16 | enabled: 0 17 | settings: {} 18 | - first: 19 | Editor: Editor 20 | second: 21 | enabled: 0 22 | settings: 23 | DefaultValueInitialized: true 24 | - first: 25 | iPhone: iOS 26 | second: 27 | enabled: 1 28 | settings: {} 29 | - first: 30 | tvOS: tvOS 31 | second: 32 | enabled: 1 33 | settings: {} 34 | userData: 35 | assetBundleName: 36 | assetBundleVariant: 37 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/PluginMsgInterface.mm.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d1952d9d8280254aa9599a412a59fca 3 | timeCreated: 1562335736 4 | licenseType: Free 5 | PluginImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | iconMap: {} 9 | executionOrder: {} 10 | isPreloaded: 0 11 | isOverridable: 0 12 | platformData: 13 | - first: 14 | Any: 15 | second: 16 | enabled: 0 17 | settings: {} 18 | - first: 19 | Editor: Editor 20 | second: 21 | enabled: 0 22 | settings: 23 | DefaultValueInitialized: true 24 | - first: 25 | iPhone: iOS 26 | second: 27 | enabled: 1 28 | settings: {} 29 | - first: 30 | tvOS: tvOS 31 | second: 32 | enabled: 1 33 | settings: {} 34 | userData: 35 | assetBundleName: 36 | assetBundleVariant: 37 | -------------------------------------------------------------------------------- /demo/ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | m_Enabled: 0 7 | m_TestMode: 0 8 | m_TestEventUrl: 9 | m_TestConfigUrl: 10 | m_TestInitMode: 0 11 | CrashReportingSettings: 12 | m_EventUrl: https://perf-events.cloud.unity3d.com/api/events/crashes 13 | m_Enabled: 0 14 | m_CaptureEditorExceptions: 1 15 | UnityPurchasingSettings: 16 | m_Enabled: 0 17 | m_TestMode: 0 18 | UnityAnalyticsSettings: 19 | m_Enabled: 0 20 | m_InitializeOnStartup: 1 21 | m_TestMode: 0 22 | m_TestEventUrl: 23 | m_TestConfigUrl: 24 | UnityAdsSettings: 25 | m_Enabled: 0 26 | m_InitializeOnStartup: 1 27 | m_TestMode: 0 28 | m_EnabledPlatforms: 4294967295 29 | m_IosGameId: 30 | m_AndroidGameId: 31 | PerformanceReportingSettings: 32 | m_Enabled: 0 33 | -------------------------------------------------------------------------------- /src/androidProj/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /src/androidProj/nativeeditplugin/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion "28.0.3" 6 | 7 | defaultConfig { 8 | minSdkVersion 19 9 | targetSdkVersion 28 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | repositories { 22 | maven { 23 | url "https://maven.google.com" 24 | } 25 | } 26 | dependencies { 27 | compileOnly files('./libs/UnityPlayer.jar') 28 | } 29 | 30 | task clearJar(type: Delete) { 31 | delete 'build/outputs/nativeeditplugin.jar' 32 | } 33 | 34 | task makeJar(type: Copy) { 35 | from('build/intermediates/bundles/release/') 36 | into('build/outputs/') 37 | } 38 | 39 | makeJar.dependsOn(clearJar, build) -------------------------------------------------------------------------------- /demo/ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_MinPenetrationForPenalty: 0.01 17 | m_BaumgarteScale: 0.2 18 | m_BaumgarteTimeOfImpactScale: 0.75 19 | m_TimeToSleep: 0.5 20 | m_LinearSleepTolerance: 0.01 21 | m_AngularSleepTolerance: 2 22 | m_QueriesHitTriggers: 1 23 | m_QueriesStartInColliders: 1 24 | m_ChangeStopsCallbacks: 0 25 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 26 | -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Never ignore Asset meta data 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # TextMesh Pro files 17 | [Aa]ssets/TextMesh*Pro/ 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo/Rider solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | .idea/ 32 | *.csproj 33 | *.unityproj 34 | *.sln 35 | *.suo 36 | *.tmp 37 | *.user 38 | *.userprefs 39 | *.pidb 40 | *.booproj 41 | *.svd 42 | *.pdb 43 | *.mdb 44 | *.opendb 45 | *.VC.db 46 | 47 | # Unity3D generated meta files 48 | *.pidb.meta 49 | *.pdb.meta 50 | *.mdb.meta 51 | 52 | # Unity3D generated file on crash reports 53 | sysinfo.txt 54 | 55 | # Builds 56 | *.apk 57 | *.unitypackage 58 | 59 | # Crashlytics generated file 60 | crashlytics-build.properties 61 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/JsonObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // JsonObject.h 3 | // stockissue 4 | // 5 | // Created by KYUNGMIN BANG on 12/8/14. 6 | // Copyright (c) 2014 Nureka Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JsonObject : NSObject 12 | 13 | @property (nonatomic, strong) NSMutableDictionary* dict; 14 | 15 | -(id)initWithJsonData:(NSData*) json; 16 | -(id)initWithCmd:(NSString*) cmd; 17 | -(id)initWithDictionary:(NSMutableDictionary*) _dict; 18 | -(NSData*)serialize; 19 | 20 | -(void) setInt:(NSString*) key value:(int)value; 21 | -(void) setFloat:(NSString*) key value:(float)value; 22 | -(void) setBool:(NSString*) key value:(BOOL)value; 23 | -(void) setString:(NSString*) key value:(NSString*)value; 24 | -(void) setArray:(NSString*) key value:(NSArray*) value; 25 | -(void) setJsonObject:(NSString*) key value:(JsonObject*) value; 26 | 27 | -(int) getInt:(NSString*) key; 28 | -(float) getFloat:(NSString*) key; 29 | -(BOOL) getBool:(NSString*) key; 30 | -(NSString*) getString:(NSString*) key; 31 | -(NSArray*) getJsonArray:(NSString*) key; 32 | -(NSArray*) getDictArray:(NSString*) key; 33 | -(JsonObject*) getJsonObject:(NSString*) key; 34 | 35 | @end 36 | 37 | -------------------------------------------------------------------------------- /demo/ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshAreas: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/EditBox_iOS.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "JsonObject.h" 4 | 5 | /// UnityEditBox Plugin 6 | /// Written by bkmin 2014/11 Nureka Inc. 7 | 8 | #define MSG_CREATE @"CreateEdit" 9 | #define MSG_REMOVE @"RemoveEdit" 10 | #define MSG_SET_TEXT @"SetText" 11 | #define MSG_GET_TEXT @"GetText" 12 | #define MSG_SET_RECT @"SetRect" 13 | #define MSG_SET_TEXTSIZE @"SetTextSize" 14 | #define MSG_SET_FOCUS @"SetFocus" 15 | #define MSG_SET_VISIBLE @"SetVisible" 16 | #define MSG_TEXT_CHANGE @"TextChange" 17 | #define MSG_TEXT_BEGIN_EDIT @"TextBeginEdit" 18 | #define MSG_TEXT_END_EDIT @"TextEndEdit" 19 | #define MSG_RETURN_PRESSED @"ReturnPressed" 20 | 21 | @interface EditBox : NSObject 22 | { 23 | UIView* editView; 24 | UIViewController* viewController; 25 | UIToolbar* keyboardDoneButtonView; 26 | UIBarButtonItem* doneButton; 27 | int tag; 28 | } 29 | 30 | @property (nonatomic, assign) int maxLength; 31 | 32 | +(void) initializeEditBox:(UIViewController*) _unityViewController unityName:(const char*) unityName; 33 | +(JsonObject*) processRecvJsonMsg:(int)nSenderId msg:(JsonObject*) jsonMsg; 34 | +(void) finalizeEditBox; 35 | 36 | -(void) hideKeyboard; 37 | -(BOOL) isFocused; 38 | @end 39 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/Android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 14 | 15 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/androidProj/.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | *.aab 5 | 6 | # Files for the ART/Dalvik VM 7 | *.dex 8 | 9 | # Java class files 10 | *.class 11 | 12 | # Generated files 13 | bin/ 14 | gen/ 15 | out/ 16 | release/ 17 | 18 | # Gradle files 19 | .gradle/ 20 | build/ 21 | 22 | # Local configuration file (sdk path, etc) 23 | local.properties 24 | 25 | # Proguard folder generated by Eclipse 26 | proguard/ 27 | 28 | # Log Files 29 | *.log 30 | 31 | # Android Studio Navigation editor temp files 32 | .navigation/ 33 | 34 | # Android Studio captures folder 35 | captures/ 36 | 37 | # IntelliJ 38 | *.iml 39 | .idea/workspace.xml 40 | .idea/tasks.xml 41 | .idea/gradle.xml 42 | .idea/assetWizardSettings.xml 43 | .idea/dictionaries 44 | .idea/libraries 45 | # Android Studio 3 in .gitignore file. 46 | .idea/caches 47 | .idea/modules.xml 48 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 49 | .idea/navEditor.xml 50 | 51 | # Keystore files 52 | # Uncomment the following lines if you do not want to check your keystore files in. 53 | #*.jks 54 | #*.keystore 55 | 56 | # External native build folder generated in Android Studio 2.2 and later 57 | .externalNativeBuild 58 | 59 | # Google Services (e.g. APIs or Firebase) 60 | # google-services.json 61 | 62 | # Freeline 63 | freeline.py 64 | freeline/ 65 | freeline_project_description.json 66 | 67 | # fastlane 68 | fastlane/report.xml 69 | fastlane/Preview.html 70 | fastlane/screenshots 71 | fastlane/test_output 72 | fastlane/readme.md 73 | 74 | # Version control 75 | vcs.xml 76 | 77 | # lint 78 | lint/intermediates/ 79 | lint/generated/ 80 | lint/outputs/ 81 | lint/tmp/ 82 | # lint/reports/ 83 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/PluginMsgReceiver.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Kyungmin Bang 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | using UnityEngine; 25 | 26 | public abstract class PluginMsgReceiver : MonoBehaviour 27 | { 28 | private int _receiverId; 29 | 30 | protected virtual void Start() 31 | { 32 | _receiverId = PluginMsgHandler.GetInstanceForReceiver(this).RegisterAndGetReceiverId(this); 33 | } 34 | 35 | protected virtual void OnDestroy() 36 | { 37 | PluginMsgHandler.GetInstanceForReceiver(this).RemoveReceiver(_receiverId); 38 | } 39 | 40 | protected JsonObject SendPluginMsg(JsonObject jsonMsg) 41 | { 42 | return PluginMsgHandler.GetInstanceForReceiver(this).SendMsgToPlugin(_receiverId, jsonMsg); 43 | } 44 | 45 | public abstract void OnPluginMsgDirect(JsonObject jsonMsg); 46 | } -------------------------------------------------------------------------------- /demo/ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 12 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10782, guid: 0000000000000000f000000000000000, type: 0} 38 | - {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0} 39 | - {fileID: 16002, guid: 0000000000000000f000000000000000, type: 0} 40 | - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0} 41 | m_PreloadedShaders: [] 42 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 43 | type: 0} 44 | m_CustomRenderPipeline: {fileID: 0} 45 | m_TransparencySortMode: 0 46 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 47 | m_DefaultRenderingPath: 1 48 | m_DefaultMobileRenderingPath: 1 49 | m_TierSettings: [] 50 | m_LightmapStripping: 0 51 | m_FogStripping: 0 52 | m_InstancingStripping: 0 53 | m_LightmapKeepPlain: 1 54 | m_LightmapKeepDirCombined: 1 55 | m_LightmapKeepDynamicPlain: 1 56 | m_LightmapKeepDynamicDirCombined: 1 57 | m_LightmapKeepShadowMask: 1 58 | m_LightmapKeepSubtractive: 1 59 | m_FogKeepLinear: 1 60 | m_FogKeepExp: 1 61 | m_FogKeepExp2: 1 62 | m_AlbedoSwatchInfos: [] 63 | m_LightsUseLinearIntensity: 0 64 | m_LightsUseColorTemperature: 0 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## UnityNativeEdit v1.6 2 | Unity Native Input Plugin for both iOS and Android (UGUI InputField compatible). 3 | 4 | This means you don't need a separate 'Unity' Input box and you can use all native text functions such as `Select`, `Copy` and `Paste`. 5 | 6 | ### Usage 7 | 1. Simply copy the files in `release/NativeEditPlugin` into your existing unity project asset folder. 8 | 2. Attach ```NativeEditBox``` script to your UnityUI ```InputField```object. 9 | 3. Build and run on your android or ios device! 10 | 11 | ### Building the Android plugin 12 | If you want to tinker with the project yourself you need to build the Android project again in AndroidStudio (for iOS you can just modify the Objective-C code and it will get built at the same time as the Unity project). 13 | 14 | 1. Open the `src/androidProj` directory in AndroidStudio. 15 | 2. Select View -> Tool Windows -> Gradle in AndroidStudio. 16 | 3. In Gradle run the :nativeeditplugin -> other -> makeJar task. 17 | 4. It's a bit confusing but the task seems to generate .aar files (even though it was called makeJar, not sure what's up with that) in the `src/androidProj/nativeeditplugin/build/outputs/aar` directory. 18 | 5. To test in the demo Unity project copy the `nativeeditplugin-release.aar` file (from the output directory) to the `release\NativeEditPlugin\Plugins\Android` directory. This file is symlinked to the Unity demo project. 19 | 20 | ### Etc 21 | 1. NativeEditBox will work with delegate defined in your Unity UI InputField, `On Value Change` and `End Edit` 22 | 2. It's open source and free to use/redistribute! 23 | 24 | - - - 25 | ## UnityNativeEdit v1.6 中文说明 26 | UnityNativeEdit是适用于Unity、支持iOS和Android的原生输入框插件,免去直接使用UGUI的InputField产生的键盘方面的不便,并且可以和原生应用一样方便地对输入文本进行选择、复制和粘贴等操作。 27 | 28 | 本repo的1.6版本针对[原版](https://github.com/YousicianGit/UnityNativeEdit/)进行了各种优化和bug修复,无需像原版那样要事先挂载`PluginMsgHandler`脚本,并且自2017年起被某国产知名二次元手机游戏使用。 29 | 30 | ### 使用方法 31 | 1. 直接拷贝`release/NativeEditPlugin`目录下的文件到你的项目中; 32 | 2. 在你的InputField对象上添加`NativeEditBox`脚本组件。 33 | 34 | 添加后,如果要通过代码修改输入框的文本的话,请务必通过`NativeEditBox`脚本的`text`属性进行操作,否则将不会看到修改后的文本。 35 | 3. 发布到真机上试试吧! 36 | 37 | ### 生成插件 38 | 如果你想自行修改插件,对安卓平台而言,你需要在Android Studio中重新生成;而对iOS平台而言,只需修改 Objective-C 代码即可。 39 | 40 | 1. 在Android Studio中打开文件夹`src/androidProj`; 41 | 2. 选择 View -> Tool Windows -> Gradle ; 42 | 3. 运行 :nativeeditplugin -> other -> makeJar 任务; 43 | 4. 该任务会在`src/androidProj/nativeeditplugin/build/outputs/aar`下生成.aar文件(即使任务名字叫做makeJar); 44 | 5. 拷贝`nativeeditplugin-release.aar`至`release\NativeEditPlugin\Plugins\Android`文件夹。 45 | 46 | ### Etc 47 | 1. 本插件可以响应同一GameObject上的InputField的`OnValueChanged`和`OnEndEdit`事件。 48 | 2. 本插件开源且可免费使用、分发。 49 | -------------------------------------------------------------------------------- /src/androidProj/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/androidProj/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 25 | 40 | 41 | 42 | 43 | 44 | 45 | 47 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/PluginMsgInterface.mm: -------------------------------------------------------------------------------- 1 | // 2 | // PluginMsgHandler.m 3 | // Unity-iPhone 4 | // 5 | // Created by KYUNGMIN BANG on 2/24/15. 6 | // 7 | // 8 | 9 | #import "EditBox_iOS.h" 10 | 11 | UIViewController* UnityGetGLViewController(); 12 | 13 | char* gCopyString(const char* string) { 14 | if(string == NULL) { 15 | return NULL; 16 | } 17 | char* ret = (char*) malloc(strlen(string) + 1); // memory will be auto-freed by unity 18 | strcpy(ret, string); 19 | return ret; 20 | } 21 | 22 | extern "C" { 23 | 24 | /* typedef void* MonoDomain; 25 | typedef void* MonoAssembly; 26 | typedef void* MonoImage; 27 | typedef void* MonoClass; 28 | typedef void* MonoObject; 29 | typedef void* MonoMethodDesc; 30 | typedef void* MonoMethod; 31 | typedef void* gpointer; 32 | typedef int gboolean; 33 | 34 | MonoDomain *mono_domain_get(); 35 | MonoAssembly *mono_domain_assembly_open(MonoDomain *domain, const char *assemblyName); 36 | MonoImage *mono_assembly_get_image(MonoAssembly *assembly); 37 | MonoMethodDesc *mono_method_desc_new(const char *methodString, gboolean useNamespace); 38 | MonoMethodDesc *mono_method_desc_free(MonoMethodDesc *desc); 39 | MonoMethod *mono_method_desc_search_in_image(MonoMethodDesc *methodDesc, MonoImage *image); 40 | MonoObject *mono_runtime_invoke(MonoMethod *method, void *obj, void **params, MonoObject **exc); 41 | gpointer mono_object_unbox(MonoObject *obj); 42 | 43 | void initializUnityPluginHandler() 44 | { 45 | MonoDomain *domain = mono_domain_get(); 46 | NSString *assemblyPath = [[[NSBundle mainBundle] bundlePath] 47 | stringByAppendingPathComponent:@"Data/Managed/Assembly-CSharp.dll"]; 48 | MonoAssembly *assembly = mono_domain_assembly_open(domain, assemblyPath.UTF8String); 49 | MonoImage *image = mono_assembly_get_image(assembly); 50 | 51 | MonoMethodDesc *desc = mono_method_desc_new("PluginMsgHandler:InitializeHandlerByNative()", FALSE); 52 | MonoMethod *method = mono_method_desc_search_in_image(desc, image); 53 | mono_runtime_invoke(method, NULL, NULL, NULL); 54 | mono_method_desc_free(desc); 55 | } */ 56 | 57 | void _iOS_InitPluginMsgHandler(const char* unityName) 58 | { 59 | [EditBox initializeEditBox:UnityGetGLViewController() unityName:unityName]; 60 | NSLog(@"_iOS_InitPluginMsgHandler called"); 61 | } 62 | 63 | char* _iOS_SendUnityMsgToPlugin(int nSenderId, const char* jsonMsgApp) 64 | { 65 | NSString* strJson = [NSString stringWithUTF8String:jsonMsgApp]; 66 | JsonObject* jsonMsg = [[JsonObject alloc] initWithJsonData:[strJson dataUsingEncoding:NSUTF8StringEncoding]]; 67 | JsonObject* jsonRet = [EditBox processRecvJsonMsg:nSenderId msg:jsonMsg]; 68 | 69 | NSString* strRet = [[NSString alloc] initWithData:[jsonRet serialize] encoding:NSUTF8StringEncoding]; 70 | return gCopyString([strRet UTF8String]); 71 | } 72 | void _iOS_ClosePluginMsgHandler() 73 | { 74 | [EditBox finalizeEditBox]; 75 | } 76 | } -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/PlaceholderTextView.m: -------------------------------------------------------------------------------- 1 | #import "PlaceholderTextView.h" 2 | #import "EditBox_iOS.h" 3 | 4 | @interface PlaceholderTextView () 5 | 6 | @property (unsafe_unretained, nonatomic, readonly) NSString* realText; 7 | 8 | - (void) beginEditing:(NSNotification*) notification; 9 | - (void) endEditing:(NSNotification*) notification; 10 | 11 | @end 12 | 13 | @implementation PlaceholderTextView 14 | 15 | @synthesize realTextColor; 16 | @synthesize placeholder; 17 | @synthesize placeholderColor; 18 | 19 | #pragma mark - 20 | #pragma mark Initialisation 21 | 22 | - (id) initWithFrame:(CGRect)frame { 23 | if ((self = [super initWithFrame:frame])) { 24 | [self awakeFromNib]; 25 | } 26 | return self; 27 | } 28 | 29 | - (void)awakeFromNib { 30 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginEditing:) name:UITextViewTextDidBeginEditingNotification object:self]; 31 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endEditing:) name:UITextViewTextDidEndEditingNotification object:self]; 32 | 33 | self.realTextColor = self.textColor; 34 | self.placeholderColor = [UIColor lightGrayColor]; 35 | } 36 | 37 | #pragma mark - 38 | #pragma mark Setter/Getters 39 | 40 | - (void) setPlaceholder:(NSString *)aPlaceholder { 41 | if ([self.realText isEqualToString:placeholder] && ![self isFirstResponder]) { 42 | self.text = aPlaceholder; 43 | } 44 | if (aPlaceholder != placeholder) { 45 | placeholder = aPlaceholder; 46 | } 47 | 48 | 49 | [self endEditing:nil]; 50 | } 51 | 52 | - (void)setPlaceholderColor:(UIColor *)aPlaceholderColor { 53 | placeholderColor = aPlaceholderColor; 54 | 55 | if ([super.text isEqualToString:self.placeholder]) { 56 | self.textColor = self.placeholderColor; 57 | } 58 | } 59 | 60 | - (NSString *) text { 61 | NSString* text = [super text]; 62 | if ([text isEqualToString:self.placeholder]) return @""; 63 | return text; 64 | } 65 | 66 | - (void) setText:(NSString *)text { 67 | if (([text isEqualToString:@""] || text == nil) && ![self isFirstResponder]) { 68 | super.text = self.placeholder; 69 | } 70 | else { 71 | super.text = text; 72 | } 73 | 74 | if ([text isEqualToString:self.placeholder] || text == nil) { 75 | self.textColor = self.placeholderColor; 76 | } 77 | else { 78 | self.textColor = self.realTextColor; 79 | } 80 | } 81 | 82 | - (NSString *) realText { 83 | return [super text]; 84 | } 85 | 86 | - (void) beginEditing:(NSNotification*) notification { 87 | if ([self.realText isEqualToString:self.placeholder]) { 88 | super.text = nil; 89 | self.textColor = self.realTextColor; 90 | } 91 | } 92 | 93 | - (void) endEditing:(NSNotification*) notification { 94 | if ([self.realText isEqualToString:@""] || self.realText == nil) { 95 | super.text = self.placeholder; 96 | self.textColor = self.placeholderColor; 97 | } 98 | } 99 | 100 | - (void) setTextColor:(UIColor *)textColor { 101 | if ([self.realText isEqualToString:self.placeholder]) { 102 | if ([textColor isEqual:self.placeholderColor]){ 103 | [super setTextColor:textColor]; 104 | } else { 105 | self.realTextColor = textColor; 106 | } 107 | } 108 | else { 109 | self.realTextColor = textColor; 110 | [super setTextColor:textColor]; 111 | } 112 | } 113 | 114 | -(void) SetEditbox:(NSObject*)box 115 | { 116 | _editBox = box; 117 | 118 | } 119 | 120 | #pragma mark - 121 | #pragma mark Dealloc 122 | 123 | - (void)dealloc { 124 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 125 | 126 | } 127 | 128 | @end -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/JsonObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // JsonObject.m 3 | // stockissue 4 | // 5 | // Created by KYUNGMIN BANG on 12/8/14. 6 | // Copyright (c) 2014 Nureka Inc. All rights reserved. 7 | // 8 | 9 | #import "JsonObject.h" 10 | 11 | 12 | @implementation JsonObject 13 | @synthesize dict; 14 | 15 | -(void) dealloc 16 | { 17 | dict = nil; 18 | } 19 | 20 | -(id)init 21 | { 22 | self = [super init]; 23 | if (self) 24 | { 25 | dict = [[NSMutableDictionary alloc] init]; 26 | 27 | } 28 | return self; 29 | } 30 | 31 | -(id)initWithDictionary:(NSMutableDictionary*) _dict 32 | { 33 | self = [super init]; 34 | if (self) 35 | { 36 | dict = _dict; 37 | 38 | } 39 | return self; 40 | } 41 | 42 | -(id)initWithJsonData:(NSData*) json 43 | { 44 | self = [super init]; 45 | if (self) 46 | { 47 | NSError *error; 48 | 49 | dict = [NSJSONSerialization 50 | JSONObjectWithData:json 51 | options:NSJSONReadingMutableContainers 52 | error:&error]; 53 | if (dict == nil) 54 | { 55 | NSLog(@"Json parse error %@",[error description]); 56 | } 57 | } 58 | return self; 59 | } 60 | -(id)initWithCmd:(NSString*) cmd 61 | { 62 | self = [self init]; 63 | if (dict) 64 | { 65 | dict[@"cmd"] = cmd; 66 | } 67 | return self; 68 | } 69 | 70 | -(NSData*)serialize 71 | { 72 | NSError *error; 73 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict 74 | options:0 75 | error:&error]; 76 | return jsonData; 77 | } 78 | 79 | -(void) setInt:(NSString*) key value:(int)value 80 | { 81 | dict[key] = [NSNumber numberWithInt:value]; 82 | } 83 | -(void) setFloat:(NSString*) key value:(float)value 84 | { 85 | dict[key] = [NSNumber numberWithFloat:value]; 86 | } 87 | -(void) setBool:(NSString*) key value:(BOOL)value 88 | { 89 | dict[key] = [NSNumber numberWithBool:value]; 90 | } 91 | -(void) setString:(NSString*) key value:(NSString*)value 92 | { 93 | dict[key] = value; 94 | } 95 | -(void) setArray:(NSString*) key value:(NSArray*) value 96 | { 97 | dict[key] = value; 98 | } 99 | -(void) setJsonObject:(NSString*) key value:(JsonObject*) value 100 | { 101 | dict[key] = value.dict; 102 | } 103 | 104 | -(int) getInt:(NSString*) key 105 | { 106 | id obj = [dict objectForKey:key]; 107 | if (obj == nil || obj == (id)[NSNull null]) return 0; 108 | return [obj intValue]; 109 | } 110 | -(float) getFloat:(NSString*) key 111 | { 112 | id obj = [dict objectForKey:key]; 113 | if (obj == nil || obj == (id)[NSNull null]) return 0.0f; 114 | return [obj floatValue]; 115 | } 116 | -(BOOL) getBool:(NSString*) key 117 | { 118 | id obj = [dict objectForKey:key]; 119 | if (obj == nil || obj == (id)[NSNull null]) return NO; 120 | return [obj boolValue]; 121 | } 122 | -(NSString*) getString:(NSString*) key 123 | { 124 | id obj = [dict objectForKey:key]; 125 | if (!obj || obj == (id)[NSNull null]) return @""; 126 | return (NSString*) obj; 127 | } 128 | -(NSArray*) getDictArray:(NSString*) key 129 | { 130 | id obj = [dict objectForKey:key]; 131 | if (obj == nil || obj == (id)[NSNull null]) return [[NSArray alloc] init]; 132 | return (NSArray*) obj; 133 | } 134 | -(NSArray*) getJsonArray:(NSString*) key 135 | { 136 | id obj = [dict objectForKey:key]; 137 | NSMutableArray* arr = [[NSMutableArray alloc] init]; 138 | if (obj == nil || obj == (id)[NSNull null]) return arr; 139 | for (id arrObj in (NSMutableArray*) obj) { 140 | JsonObject* newObj = [[JsonObject alloc] initWithDictionary:(NSMutableDictionary*) arrObj]; 141 | [arr addObject:newObj]; 142 | } 143 | return (NSArray*) arr; 144 | } 145 | -(JsonObject*) getJsonObject:(NSString*) key 146 | { 147 | id obj = [dict objectForKey:key]; 148 | JsonObject* newObj = [[JsonObject alloc] init]; 149 | if (obj == nil || obj == (id)[NSNull null]) return newObj; 150 | newObj.dict = (NSMutableDictionary*) obj; 151 | return newObj; 152 | } 153 | 154 | @end 155 | -------------------------------------------------------------------------------- /src/androidProj/nativeeditplugin/src/main/java/com/bkmin/android/NativeEditPlugin.java: -------------------------------------------------------------------------------- 1 | package com.bkmin.android; 2 | 3 | import android.app.Activity; 4 | import android.util.Log; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.RelativeLayout; 8 | 9 | import com.unity3d.player.UnityPlayer; 10 | 11 | import org.json.JSONObject; 12 | 13 | public class NativeEditPlugin { 14 | public static Activity unityActivity; 15 | public static ViewGroup rootView; 16 | private static RelativeLayout mainLayout; 17 | private static ViewGroup topViewGroup; 18 | private static String unityName = ""; 19 | 20 | static final String LOG_TAG = "NativeEditPlugin"; 21 | 22 | private static View getLeafView(View view) { 23 | if (view instanceof ViewGroup) { 24 | ViewGroup vg = (ViewGroup) view; 25 | for (int i = 0; i < vg.getChildCount(); ++i) { 26 | View childView = vg.getChildAt(i); 27 | View result = getLeafView(childView); 28 | if (result != null) 29 | return result; 30 | } 31 | return null; 32 | } else { 33 | Log.i(LOG_TAG, "Found leaf view"); 34 | return view; 35 | } 36 | } 37 | 38 | @SuppressWarnings("unused") 39 | public static void InitPluginMsgHandler(final String _unityName) { 40 | unityActivity = UnityPlayer.currentActivity; 41 | unityName = _unityName; 42 | 43 | unityActivity.runOnUiThread(new Runnable() { 44 | public void run() { 45 | if (mainLayout != null) 46 | topViewGroup.removeView(mainLayout); 47 | 48 | rootView = unityActivity.findViewById(android.R.id.content); 49 | View topMostView = getLeafView(rootView); 50 | topViewGroup = (ViewGroup) topMostView.getParent(); 51 | mainLayout = new RelativeLayout(unityActivity); 52 | RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams( 53 | RelativeLayout.LayoutParams.MATCH_PARENT, 54 | RelativeLayout.LayoutParams.MATCH_PARENT); 55 | topViewGroup.addView(mainLayout, rlp); 56 | 57 | rootView.setOnSystemUiVisibilityChangeListener 58 | (new View.OnSystemUiVisibilityChangeListener() { 59 | @Override 60 | public void onSystemUiVisibilityChange(int visibility) { 61 | int systemUiVisibilitySettings = 62 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 63 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 64 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 65 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 66 | | View.SYSTEM_UI_FLAG_FULLSCREEN 67 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 68 | rootView.setSystemUiVisibility(systemUiVisibilitySettings); 69 | } 70 | }); 71 | } 72 | }); 73 | } 74 | 75 | @SuppressWarnings("unused") 76 | public static void ClosePluginMsgHandler() { 77 | unityActivity.runOnUiThread(new Runnable() { 78 | public void run() { 79 | topViewGroup.removeView(mainLayout); 80 | } 81 | }); 82 | } 83 | 84 | public static void SendUnityMessage(JSONObject jsonMsg) { 85 | UnityPlayer.UnitySendMessage(unityName, "OnMsgFromPlugin", jsonMsg.toString()); 86 | } 87 | 88 | @SuppressWarnings("unused") 89 | public static String SendUnityMsgToPlugin(final int nSenderId, final String jsonMsg) { 90 | final Runnable task = new Runnable() { 91 | public void run() { 92 | EditBox.processRecvJsonMsg(mainLayout, nSenderId, jsonMsg); 93 | } 94 | }; 95 | unityActivity.runOnUiThread(task); 96 | return new JSONObject().toString(); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/JsonObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MiniJSON_Min; 4 | using Object = UnityEngine.Object; 5 | 6 | /* 7 | * Copyright (c) 2015 Kyungmin Bang 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining 10 | * a copy of this software and associated documentation files (the 11 | * "Software"), to deal in the Software without restriction, including 12 | * without limitation the rights to use, copy, modify, merge, publish, 13 | * distribute, sublicense, and/or sell copies of the Software, and to 14 | * permit persons to whom the Software is furnished to do so, subject to 15 | * the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | 30 | /// 31 | /// JsonObject provide safe and type-compatible wrapper to access Json Element 32 | /// Safe means, even if a certain Json doesn't contain 'key', it doesn't crash. 33 | /// 34 | public class JsonObject : Object 35 | { 36 | /// 37 | /// Supported object type : double, bool, string, List, Array! 38 | /// 39 | public Dictionary objectDict; 40 | 41 | public JsonObject() 42 | { 43 | objectDict = new Dictionary(); 44 | } 45 | 46 | public JsonObject(string strJson) 47 | { 48 | objectDict = Json.Deserialize(strJson) as Dictionary; 49 | } 50 | 51 | public JsonObject(Dictionary dict) 52 | { 53 | objectDict = dict; 54 | } 55 | 56 | public object this[string key] 57 | { 58 | get { return objectDict[key]; } 59 | set { objectDict[key] = value; } 60 | } 61 | 62 | public string getCmd() 63 | { 64 | return (string) objectDict["cmd"]; 65 | } 66 | 67 | public string Serialize() 68 | { 69 | var strData = Json.Serialize(objectDict); 70 | return strData; 71 | } 72 | 73 | //// Deserialize helper 74 | 75 | private object GetDictValue(string key) 76 | { 77 | object obj; 78 | if(objectDict.TryGetValue(key, out obj)) 79 | return obj ?? ""; 80 | return ""; 81 | } 82 | 83 | public bool KeyExist(string key) 84 | { 85 | object obj; 86 | if(objectDict.TryGetValue(key, out obj)) 87 | return true; 88 | return false; 89 | } 90 | 91 | public Dictionary GetJsonDict(string key) 92 | { 93 | object obj; 94 | if(objectDict.TryGetValue(key, out obj)) 95 | return (Dictionary) obj; 96 | return new Dictionary(); 97 | } 98 | 99 | public JsonObject GetJsonObject(string key) 100 | { 101 | var dict = GetJsonDict(key); 102 | return new JsonObject(dict); 103 | } 104 | 105 | public bool GetBool(string key) 106 | { 107 | bool val; 108 | if(bool.TryParse(GetDictValue(key).ToString(), out val)) return val; 109 | return false; 110 | } 111 | 112 | public int GetInt(string key) 113 | { 114 | int val; 115 | if(int.TryParse(GetDictValue(key).ToString(), out val)) return val; 116 | return 0; 117 | } 118 | 119 | public float GetFloat(string key) 120 | { 121 | float val; 122 | if(float.TryParse(GetDictValue(key).ToString(), out val)) return val; 123 | return 0.0f; 124 | } 125 | 126 | public string GetString(string key) 127 | { 128 | return GetDictValue(key).ToString(); 129 | } 130 | 131 | public object GetEnum(Type type, string key) 132 | { 133 | var obj = (string) GetDictValue(key); 134 | if(obj.Length > 0) 135 | return Enum.Parse(type, obj); 136 | return 0; 137 | } 138 | 139 | public List GetListJsonObject(string key) 140 | { 141 | object obj; 142 | var retList = new List(); 143 | if(objectDict.TryGetValue(key, out obj)) 144 | foreach(var elem in (List) obj) 145 | retList.Add(new JsonObject((Dictionary) elem)); 146 | return retList; 147 | } 148 | } -------------------------------------------------------------------------------- /demo/ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!47 &1 4 | QualitySettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 5 7 | m_CurrentQuality: 5 8 | m_QualitySettings: 9 | - serializedVersion: 2 10 | name: Fastest 11 | pixelLightCount: 0 12 | shadows: 0 13 | shadowResolution: 0 14 | shadowProjection: 1 15 | shadowCascades: 1 16 | shadowDistance: 15 17 | shadowNearPlaneOffset: 2 18 | shadowCascade2Split: 0.33333334 19 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 20 | blendWeights: 1 21 | textureQuality: 1 22 | anisotropicTextures: 0 23 | antiAliasing: 0 24 | softParticles: 0 25 | softVegetation: 0 26 | realtimeReflectionProbes: 0 27 | billboardsFaceCameraPosition: 0 28 | vSyncCount: 0 29 | lodBias: 0.3 30 | maximumLODLevel: 0 31 | particleRaycastBudget: 4 32 | asyncUploadTimeSlice: 2 33 | asyncUploadBufferSize: 4 34 | excludedTargetPlatforms: [] 35 | - serializedVersion: 2 36 | name: Fast 37 | pixelLightCount: 0 38 | shadows: 0 39 | shadowResolution: 0 40 | shadowProjection: 1 41 | shadowCascades: 1 42 | shadowDistance: 20 43 | shadowNearPlaneOffset: 2 44 | shadowCascade2Split: 0.33333334 45 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 46 | blendWeights: 2 47 | textureQuality: 0 48 | anisotropicTextures: 0 49 | antiAliasing: 0 50 | softParticles: 0 51 | softVegetation: 0 52 | realtimeReflectionProbes: 0 53 | billboardsFaceCameraPosition: 0 54 | vSyncCount: 0 55 | lodBias: 0.4 56 | maximumLODLevel: 0 57 | particleRaycastBudget: 16 58 | asyncUploadTimeSlice: 2 59 | asyncUploadBufferSize: 4 60 | excludedTargetPlatforms: [] 61 | - serializedVersion: 2 62 | name: Simple 63 | pixelLightCount: 1 64 | shadows: 1 65 | shadowResolution: 0 66 | shadowProjection: 1 67 | shadowCascades: 1 68 | shadowDistance: 20 69 | shadowNearPlaneOffset: 2 70 | shadowCascade2Split: 0.33333334 71 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 72 | blendWeights: 2 73 | textureQuality: 0 74 | anisotropicTextures: 1 75 | antiAliasing: 0 76 | softParticles: 0 77 | softVegetation: 0 78 | realtimeReflectionProbes: 0 79 | billboardsFaceCameraPosition: 0 80 | vSyncCount: 0 81 | lodBias: 0.7 82 | maximumLODLevel: 0 83 | particleRaycastBudget: 64 84 | asyncUploadTimeSlice: 2 85 | asyncUploadBufferSize: 4 86 | excludedTargetPlatforms: [] 87 | - serializedVersion: 2 88 | name: Good 89 | pixelLightCount: 2 90 | shadows: 2 91 | shadowResolution: 1 92 | shadowProjection: 1 93 | shadowCascades: 2 94 | shadowDistance: 40 95 | shadowNearPlaneOffset: 2 96 | shadowCascade2Split: 0.33333334 97 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 98 | blendWeights: 2 99 | textureQuality: 0 100 | anisotropicTextures: 1 101 | antiAliasing: 0 102 | softParticles: 0 103 | softVegetation: 1 104 | realtimeReflectionProbes: 1 105 | billboardsFaceCameraPosition: 1 106 | vSyncCount: 1 107 | lodBias: 1 108 | maximumLODLevel: 0 109 | particleRaycastBudget: 256 110 | asyncUploadTimeSlice: 2 111 | asyncUploadBufferSize: 4 112 | excludedTargetPlatforms: [] 113 | - serializedVersion: 2 114 | name: Beautiful 115 | pixelLightCount: 3 116 | shadows: 2 117 | shadowResolution: 2 118 | shadowProjection: 1 119 | shadowCascades: 2 120 | shadowDistance: 70 121 | shadowNearPlaneOffset: 2 122 | shadowCascade2Split: 0.33333334 123 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 124 | blendWeights: 4 125 | textureQuality: 0 126 | anisotropicTextures: 2 127 | antiAliasing: 2 128 | softParticles: 1 129 | softVegetation: 1 130 | realtimeReflectionProbes: 1 131 | billboardsFaceCameraPosition: 1 132 | vSyncCount: 1 133 | lodBias: 1.5 134 | maximumLODLevel: 0 135 | particleRaycastBudget: 1024 136 | asyncUploadTimeSlice: 2 137 | asyncUploadBufferSize: 4 138 | excludedTargetPlatforms: [] 139 | - serializedVersion: 2 140 | name: Fantastic 141 | pixelLightCount: 4 142 | shadows: 2 143 | shadowResolution: 2 144 | shadowProjection: 1 145 | shadowCascades: 4 146 | shadowDistance: 150 147 | shadowNearPlaneOffset: 2 148 | shadowCascade2Split: 0.33333334 149 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 150 | blendWeights: 4 151 | textureQuality: 0 152 | anisotropicTextures: 2 153 | antiAliasing: 2 154 | softParticles: 1 155 | softVegetation: 1 156 | realtimeReflectionProbes: 1 157 | billboardsFaceCameraPosition: 1 158 | vSyncCount: 1 159 | lodBias: 2 160 | maximumLODLevel: 0 161 | particleRaycastBudget: 4096 162 | asyncUploadTimeSlice: 2 163 | asyncUploadBufferSize: 4 164 | excludedTargetPlatforms: [] 165 | m_PerPlatformDefaultQuality: 166 | Android: 2 167 | BlackBerry: 2 168 | GLES Emulation: 5 169 | PS3: 5 170 | PS4: 5 171 | PSM: 5 172 | PSP2: 5 173 | Samsung TV: 2 174 | Standalone: 5 175 | Tizen: 2 176 | WP8: 5 177 | Web: 5 178 | WebGL: 3 179 | Windows Store Apps: 5 180 | XBOX360: 5 181 | XboxOne: 5 182 | iPhone: 2 183 | -------------------------------------------------------------------------------- /src/androidProj/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/PluginMsgHandler.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Kyungmin Bang 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | using UnityEngine; 25 | using System.Collections; 26 | using System.Collections.Generic; 27 | using System.Runtime.InteropServices; 28 | using System; 29 | using System.IO; 30 | using AOT; 31 | 32 | public class PluginMsgHandler : MonoBehaviour 33 | { 34 | private static PluginMsgHandler _instance; 35 | 36 | private int _curReceiverIndex; 37 | private Dictionary _receiverDict; 38 | 39 | private const string DEFAULT_NAME = "NativeEditPluginHandler"; 40 | 41 | private bool isEditor 42 | { 43 | get 44 | { 45 | #if UNITY_EDITOR 46 | return true; 47 | #else 48 | return false; 49 | #endif 50 | } 51 | } 52 | 53 | private bool isStandalone 54 | { 55 | get 56 | { 57 | #if UNITY_STANDALONE 58 | return true; 59 | #else 60 | return false; 61 | #endif 62 | } 63 | } 64 | 65 | public static PluginMsgHandler GetInstanceForReceiver(PluginMsgReceiver receiver) 66 | { 67 | if(_instance == null) 68 | { 69 | var handlerObject = new GameObject(DEFAULT_NAME); 70 | _instance = handlerObject.AddComponent(); 71 | } 72 | 73 | return _instance; 74 | } 75 | 76 | private void Awake() 77 | { 78 | _receiverDict = new Dictionary(); 79 | InitializeHandler(); 80 | } 81 | 82 | private void OnDestroy() 83 | { 84 | FinalizeHandler(); 85 | _instance = null; 86 | } 87 | 88 | public int RegisterAndGetReceiverId(PluginMsgReceiver receiver) 89 | { 90 | if(receiver == null) 91 | throw new ArgumentNullException( 92 | "MonoNativeEditBox: Receiver cannot be null while RegisterAndGetReceiverId!"); 93 | 94 | var index = _curReceiverIndex; 95 | _curReceiverIndex++; 96 | 97 | _receiverDict[index] = receiver; 98 | return index; 99 | } 100 | 101 | public void RemoveReceiver(int nReceiverId) 102 | { 103 | _receiverDict.Remove(nReceiverId); 104 | if(_receiverDict.Count == 0) Destroy(_instance.gameObject); 105 | } 106 | 107 | public PluginMsgReceiver GetReceiver(int nSenderId) 108 | { 109 | return _receiverDict[nSenderId]; 110 | } 111 | 112 | private void OnMsgFromPlugin(string jsonPluginMsg) 113 | { 114 | if(jsonPluginMsg == null) return; 115 | var jsonMsg = new JsonObject(jsonPluginMsg); 116 | var nSenderId = jsonMsg.GetInt("senderId"); 117 | 118 | // In some cases the receiver might be already removed, for example if a button is pressed 119 | // that will destroy the receiver while the input field is focused an end editing message 120 | // will be sent from the plugin after the receiver is already destroyed on Unity side. 121 | if(_receiverDict.ContainsKey(nSenderId)) 122 | { 123 | var receiver = GetReceiver(nSenderId); 124 | receiver.OnPluginMsgDirect(jsonMsg); 125 | } 126 | } 127 | 128 | #if UNITY_IPHONE 129 | [DllImport ("__Internal")] 130 | private static extern void _iOS_InitPluginMsgHandler(string unityName); 131 | [DllImport ("__Internal")] 132 | private static extern string _iOS_SendUnityMsgToPlugin(int nSenderId, string strMsg); 133 | [DllImport ("__Internal")] 134 | private static extern void _iOS_ClosePluginMsgHandler(); 135 | 136 | public void InitializeHandler() 137 | { 138 | if (!isEditor) 139 | _iOS_InitPluginMsgHandler(this.name); 140 | } 141 | 142 | public void FinalizeHandler() 143 | { 144 | if (!isEditor) 145 | _iOS_ClosePluginMsgHandler(); 146 | 147 | } 148 | 149 | #elif UNITY_ANDROID 150 | private static AndroidJavaClass smAndroid; 151 | public void InitializeHandler() 152 | { 153 | if (isEditor) return; 154 | 155 | // Reinitialization was made possible on Android to be able to use as a workaround in an issue where the 156 | // NativeEditBox text would be hidden after using Unity's Handheld.PlayFullScreenMovie(). 157 | if (smAndroid == null) 158 | smAndroid = new AndroidJavaClass("com.bkmin.android.NativeEditPlugin"); 159 | smAndroid.CallStatic("InitPluginMsgHandler", name); 160 | } 161 | 162 | public void FinalizeHandler() 163 | { 164 | if (!isEditor) 165 | smAndroid.CallStatic("ClosePluginMsgHandler"); 166 | } 167 | 168 | #else 169 | public void InitializeHandler() 170 | { 171 | } 172 | 173 | public void FinalizeHandler() 174 | { 175 | } 176 | 177 | #endif 178 | 179 | 180 | public JsonObject SendMsgToPlugin(int nSenderId, JsonObject jsonMsg) 181 | { 182 | #if UNITY_EDITOR || UNITY_STANDALONE 183 | return new JsonObject(); 184 | #else 185 | jsonMsg["senderId"] = nSenderId; 186 | string strJson = jsonMsg.Serialize(); 187 | 188 | string strRet = ""; 189 | #if UNITY_IPHONE 190 | strRet = _iOS_SendUnityMsgToPlugin(nSenderId, strJson); 191 | #elif UNITY_ANDROID 192 | strRet = smAndroid.CallStatic("SendUnityMsgToPlugin", nSenderId, strJson); 193 | #endif 194 | 195 | JsonObject jsonRet = new JsonObject(strRet); 196 | return jsonRet; 197 | #endif 198 | } 199 | } -------------------------------------------------------------------------------- /src/androidProj/.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 199 | -------------------------------------------------------------------------------- /demo/ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Axes: 8 | - serializedVersion: 3 9 | m_Name: Horizontal 10 | descriptiveName: 11 | descriptiveNegativeName: 12 | negativeButton: left 13 | positiveButton: right 14 | altNegativeButton: a 15 | altPositiveButton: d 16 | gravity: 3 17 | dead: 0.001 18 | sensitivity: 3 19 | snap: 1 20 | invert: 0 21 | type: 0 22 | axis: 0 23 | joyNum: 0 24 | - serializedVersion: 3 25 | m_Name: Vertical 26 | descriptiveName: 27 | descriptiveNegativeName: 28 | negativeButton: down 29 | positiveButton: up 30 | altNegativeButton: s 31 | altPositiveButton: w 32 | gravity: 3 33 | dead: 0.001 34 | sensitivity: 3 35 | snap: 1 36 | invert: 0 37 | type: 0 38 | axis: 0 39 | joyNum: 0 40 | - serializedVersion: 3 41 | m_Name: Fire1 42 | descriptiveName: 43 | descriptiveNegativeName: 44 | negativeButton: 45 | positiveButton: left ctrl 46 | altNegativeButton: 47 | altPositiveButton: mouse 0 48 | gravity: 1000 49 | dead: 0.001 50 | sensitivity: 1000 51 | snap: 0 52 | invert: 0 53 | type: 0 54 | axis: 0 55 | joyNum: 0 56 | - serializedVersion: 3 57 | m_Name: Fire2 58 | descriptiveName: 59 | descriptiveNegativeName: 60 | negativeButton: 61 | positiveButton: left alt 62 | altNegativeButton: 63 | altPositiveButton: mouse 1 64 | gravity: 1000 65 | dead: 0.001 66 | sensitivity: 1000 67 | snap: 0 68 | invert: 0 69 | type: 0 70 | axis: 0 71 | joyNum: 0 72 | - serializedVersion: 3 73 | m_Name: Fire3 74 | descriptiveName: 75 | descriptiveNegativeName: 76 | negativeButton: 77 | positiveButton: left cmd 78 | altNegativeButton: 79 | altPositiveButton: mouse 2 80 | gravity: 1000 81 | dead: 0.001 82 | sensitivity: 1000 83 | snap: 0 84 | invert: 0 85 | type: 0 86 | axis: 0 87 | joyNum: 0 88 | - serializedVersion: 3 89 | m_Name: Jump 90 | descriptiveName: 91 | descriptiveNegativeName: 92 | negativeButton: 93 | positiveButton: space 94 | altNegativeButton: 95 | altPositiveButton: 96 | gravity: 1000 97 | dead: 0.001 98 | sensitivity: 1000 99 | snap: 0 100 | invert: 0 101 | type: 0 102 | axis: 0 103 | joyNum: 0 104 | - serializedVersion: 3 105 | m_Name: Mouse X 106 | descriptiveName: 107 | descriptiveNegativeName: 108 | negativeButton: 109 | positiveButton: 110 | altNegativeButton: 111 | altPositiveButton: 112 | gravity: 0 113 | dead: 0 114 | sensitivity: 0.1 115 | snap: 0 116 | invert: 0 117 | type: 1 118 | axis: 0 119 | joyNum: 0 120 | - serializedVersion: 3 121 | m_Name: Mouse Y 122 | descriptiveName: 123 | descriptiveNegativeName: 124 | negativeButton: 125 | positiveButton: 126 | altNegativeButton: 127 | altPositiveButton: 128 | gravity: 0 129 | dead: 0 130 | sensitivity: 0.1 131 | snap: 0 132 | invert: 0 133 | type: 1 134 | axis: 1 135 | joyNum: 0 136 | - serializedVersion: 3 137 | m_Name: Mouse ScrollWheel 138 | descriptiveName: 139 | descriptiveNegativeName: 140 | negativeButton: 141 | positiveButton: 142 | altNegativeButton: 143 | altPositiveButton: 144 | gravity: 0 145 | dead: 0 146 | sensitivity: 0.1 147 | snap: 0 148 | invert: 0 149 | type: 1 150 | axis: 2 151 | joyNum: 0 152 | - serializedVersion: 3 153 | m_Name: Horizontal 154 | descriptiveName: 155 | descriptiveNegativeName: 156 | negativeButton: 157 | positiveButton: 158 | altNegativeButton: 159 | altPositiveButton: 160 | gravity: 0 161 | dead: 0.19 162 | sensitivity: 1 163 | snap: 0 164 | invert: 0 165 | type: 2 166 | axis: 0 167 | joyNum: 0 168 | - serializedVersion: 3 169 | m_Name: Vertical 170 | descriptiveName: 171 | descriptiveNegativeName: 172 | negativeButton: 173 | positiveButton: 174 | altNegativeButton: 175 | altPositiveButton: 176 | gravity: 0 177 | dead: 0.19 178 | sensitivity: 1 179 | snap: 0 180 | invert: 1 181 | type: 2 182 | axis: 1 183 | joyNum: 0 184 | - serializedVersion: 3 185 | m_Name: Fire1 186 | descriptiveName: 187 | descriptiveNegativeName: 188 | negativeButton: 189 | positiveButton: joystick button 0 190 | altNegativeButton: 191 | altPositiveButton: 192 | gravity: 1000 193 | dead: 0.001 194 | sensitivity: 1000 195 | snap: 0 196 | invert: 0 197 | type: 0 198 | axis: 0 199 | joyNum: 0 200 | - serializedVersion: 3 201 | m_Name: Fire2 202 | descriptiveName: 203 | descriptiveNegativeName: 204 | negativeButton: 205 | positiveButton: joystick button 1 206 | altNegativeButton: 207 | altPositiveButton: 208 | gravity: 1000 209 | dead: 0.001 210 | sensitivity: 1000 211 | snap: 0 212 | invert: 0 213 | type: 0 214 | axis: 0 215 | joyNum: 0 216 | - serializedVersion: 3 217 | m_Name: Fire3 218 | descriptiveName: 219 | descriptiveNegativeName: 220 | negativeButton: 221 | positiveButton: joystick button 2 222 | altNegativeButton: 223 | altPositiveButton: 224 | gravity: 1000 225 | dead: 0.001 226 | sensitivity: 1000 227 | snap: 0 228 | invert: 0 229 | type: 0 230 | axis: 0 231 | joyNum: 0 232 | - serializedVersion: 3 233 | m_Name: Jump 234 | descriptiveName: 235 | descriptiveNegativeName: 236 | negativeButton: 237 | positiveButton: joystick button 3 238 | altNegativeButton: 239 | altPositiveButton: 240 | gravity: 1000 241 | dead: 0.001 242 | sensitivity: 1000 243 | snap: 0 244 | invert: 0 245 | type: 0 246 | axis: 0 247 | joyNum: 0 248 | - serializedVersion: 3 249 | m_Name: Submit 250 | descriptiveName: 251 | descriptiveNegativeName: 252 | negativeButton: 253 | positiveButton: return 254 | altNegativeButton: 255 | altPositiveButton: joystick button 0 256 | gravity: 1000 257 | dead: 0.001 258 | sensitivity: 1000 259 | snap: 0 260 | invert: 0 261 | type: 0 262 | axis: 0 263 | joyNum: 0 264 | - serializedVersion: 3 265 | m_Name: Submit 266 | descriptiveName: 267 | descriptiveNegativeName: 268 | negativeButton: 269 | positiveButton: enter 270 | altNegativeButton: 271 | altPositiveButton: space 272 | gravity: 1000 273 | dead: 0.001 274 | sensitivity: 1000 275 | snap: 0 276 | invert: 0 277 | type: 0 278 | axis: 0 279 | joyNum: 0 280 | - serializedVersion: 3 281 | m_Name: Cancel 282 | descriptiveName: 283 | descriptiveNegativeName: 284 | negativeButton: 285 | positiveButton: escape 286 | altNegativeButton: 287 | altPositiveButton: joystick button 1 288 | gravity: 1000 289 | dead: 0.001 290 | sensitivity: 1000 291 | snap: 0 292 | invert: 0 293 | type: 0 294 | axis: 0 295 | joyNum: 0 296 | -------------------------------------------------------------------------------- /src/androidProj/.idea/codeStyleSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 226 | 228 | -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/NativeEditBox.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Kyungmin Bang 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | 25 | /* 26 | * NativeEditBox script should be attached to Unity UI InputField object 27 | * 28 | * Limitation 29 | * 30 | * 1. Screen auto rotation is not supported. 31 | */ 32 | 33 | 34 | using System; 35 | using System.Collections; 36 | using UnityEngine; 37 | using UnityEngine.Events; 38 | using UnityEngine.UI; 39 | 40 | [RequireComponent(typeof(InputField))] 41 | public class NativeEditBox : PluginMsgReceiver 42 | { 43 | private struct EditBoxConfig 44 | { 45 | public bool multiline; 46 | public Color textColor; 47 | public Color backColor; 48 | public string contentType; 49 | public string font; 50 | public float fontSize; 51 | public string align; 52 | public string placeHolder; 53 | public int characterLimit; 54 | public Color placeHolderColor; 55 | } 56 | 57 | public enum ReturnKeyType 58 | { 59 | Default, 60 | Next, 61 | Done, 62 | Send, 63 | Go 64 | } 65 | 66 | public float androidUpdateDeltaTime = 0.15f; 67 | public bool iOSWithDoneButton = true; 68 | public bool useInputFieldFont; 69 | public bool clearFocusOnReturnPressed = true; 70 | public ReturnKeyType singleLineReturnKeyType; 71 | 72 | public event Action returnPressed; 73 | public UnityEvent onReturnPressed; // only invoke on iOS & Android 74 | public UnityEvent onBeginEdit; // only invoke on iOS & Android 75 | 76 | private bool _hasNativeEditCreated; 77 | private Text _textComponent; 78 | private bool _focusOnCreate; 79 | private bool _visibleOnCreate = true; 80 | private bool _isNowEditing; 81 | private float _fakeTimer = 0f; 82 | 83 | private EditBoxConfig _mConfig; 84 | private Camera _uiCam; 85 | private RenderMode _renderMode; 86 | 87 | private const string MSG_CREATE = "CreateEdit"; 88 | private const string MSG_REMOVE = "RemoveEdit"; 89 | private const string MSG_SET_TEXT = "SetText"; 90 | private const string MSG_SET_RECT = "SetRect"; 91 | private const string MSG_SET_TEXTSIZE = "SetTextSize"; 92 | private const string MSG_SET_FOCUS = "SetFocus"; 93 | private const string MSG_SET_VISIBLE = "SetVisible"; 94 | private const string MSG_TEXT_CHANGE = "TextChange"; 95 | private const string MSG_TEXT_BEGIN_EDIT = "TextBeginEdit"; 96 | private const string MSG_TEXT_END_EDIT = "TextEndEdit"; 97 | 98 | // to fix bug Some keys 'back' & 'enter' are eaten by unity and never arrive at plugin 99 | private const string MSG_ANDROID_KEY_DOWN = "AndroidKeyDown"; 100 | private const string MSG_RETURN_PRESSED = "ReturnPressed"; 101 | private const string MSG_GET_TEXT = "GetText"; 102 | 103 | public InputField inputField { get; private set; } 104 | 105 | public bool visible { get; private set; } 106 | 107 | public string text 108 | { 109 | get { return inputField.text; } 110 | set 111 | { 112 | inputField.text = value; 113 | if(_hasNativeEditCreated) 114 | SetTextNative(value); 115 | } 116 | } 117 | 118 | private void Awake() 119 | { 120 | inputField = GetComponent(); 121 | if(inputField == null) 122 | { 123 | Debug.LogErrorFormat("No InputField found {0} NativeEditBox Error", name); 124 | throw new MissingComponentException(); 125 | } 126 | 127 | _textComponent = inputField.textComponent; 128 | _uiCam = Camera.main; 129 | var canvas = GetComponentInParent(); 130 | if(canvas != null) _renderMode = canvas.renderMode; 131 | } 132 | 133 | // Use this for initialization 134 | protected override void Start() 135 | { 136 | base.Start(); 137 | 138 | // Wait until the end of frame before initializing to ensure that Unity UI layout has been built. We used to 139 | // initialize at Start, but that resulted in an invalid RectTransform position and size on the InputField if it 140 | // was instantiated at runtime instead of being built in to the scene. 141 | StartCoroutine(InitializeOnNextFrame()); 142 | } 143 | 144 | private void OnEnable() 145 | { 146 | if(_hasNativeEditCreated) 147 | SetVisible(true); 148 | } 149 | 150 | private void OnDisable() 151 | { 152 | if(_hasNativeEditCreated) 153 | SetVisible(false); 154 | } 155 | 156 | protected override void OnDestroy() 157 | { 158 | if(!_hasNativeEditCreated) 159 | return; 160 | 161 | RemoveNative(); 162 | base.OnDestroy(); 163 | } 164 | 165 | private void OnApplicationPause(bool pause) 166 | { 167 | if(!_hasNativeEditCreated) 168 | return; 169 | 170 | SetVisible(!pause); 171 | } 172 | 173 | private IEnumerator InitializeOnNextFrame() 174 | { 175 | yield return null; 176 | 177 | PrepareNativeEdit(); 178 | #if (UNITY_IPHONE || UNITY_ANDROID) && !UNITY_EDITOR 179 | CreateNativeEdit(); 180 | SetTextNative(inputField.text); 181 | 182 | inputField.placeholder.gameObject.SetActive(false); 183 | _textComponent.enabled = false; 184 | inputField.enabled = false; 185 | #endif 186 | } 187 | 188 | private void Update() 189 | { 190 | #if UNITY_ANDROID && !UNITY_EDITOR 191 | UpdateForceKeyeventForAndroid(); 192 | 193 | //Plugin has to update rect continually otherwise we cannot see characters inputted just now 194 | _fakeTimer += Time.deltaTime; 195 | if (inputField != null && _hasNativeEditCreated && visible 196 | && !_isNowEditing && _fakeTimer >= androidUpdateDeltaTime) 197 | { 198 | SetRectNative(_textComponent.rectTransform); 199 | _fakeTimer = 0f; 200 | } 201 | #endif 202 | } 203 | 204 | private Rect GetScreenRectFromRectTransform(RectTransform rectTransform) 205 | { 206 | var corners = new Vector3[4]; 207 | 208 | rectTransform.GetWorldCorners(corners); 209 | 210 | var xMin = float.PositiveInfinity; 211 | var xMax = float.NegativeInfinity; 212 | var yMin = float.PositiveInfinity; 213 | var yMax = float.NegativeInfinity; 214 | 215 | for(var i = 0; i < 4; i++) 216 | { 217 | var cam = _renderMode != RenderMode.ScreenSpaceOverlay ? _uiCam : null; 218 | // When screen match mode of Canvas Scaler is set to Match Width Or Height, be sure that it matches height completely or there will be mistakes. 219 | Vector3 screenCoord = RectTransformUtility.WorldToScreenPoint(cam, corners[i]); 220 | 221 | if(screenCoord.x < xMin) 222 | xMin = screenCoord.x; 223 | if(screenCoord.x > xMax) 224 | xMax = screenCoord.x; 225 | if(screenCoord.y < yMin) 226 | yMin = screenCoord.y; 227 | if(screenCoord.y > yMax) 228 | yMax = screenCoord.y; 229 | } 230 | 231 | var result = new Rect(xMin, Screen.height - yMax, xMax - xMin, yMax - yMin); 232 | return result; 233 | } 234 | 235 | private float GetNativeFontSize() 236 | { 237 | var rectScreen = GetScreenRectFromRectTransform(_textComponent.rectTransform); 238 | var fHeightRatio = rectScreen.height / _textComponent.rectTransform.rect.height; 239 | return _textComponent.fontSize * fHeightRatio; 240 | } 241 | 242 | private void PrepareNativeEdit() 243 | { 244 | var placeHolder = inputField.placeholder.GetComponent(); 245 | 246 | if(useInputFieldFont) 247 | { 248 | var font = _textComponent.font; 249 | _mConfig.font = font.fontNames.Length > 0 ? font.fontNames[0] : "Arial"; 250 | } 251 | 252 | _mConfig.placeHolder = placeHolder.text; 253 | _mConfig.placeHolderColor = placeHolder.color; 254 | _mConfig.characterLimit = inputField.characterLimit; 255 | _mConfig.fontSize = GetNativeFontSize(); 256 | _mConfig.textColor = _textComponent.color; 257 | _mConfig.align = _textComponent.alignment.ToString(); 258 | _mConfig.contentType = inputField.contentType.ToString(); 259 | _mConfig.backColor = new Color(1.0f, 1.0f, 1.0f, 0.0f); 260 | _mConfig.multiline = inputField.lineType != InputField.LineType.SingleLine; 261 | } 262 | 263 | public override void OnPluginMsgDirect(JsonObject jsonMsg) 264 | { 265 | PluginMsgHandler.GetInstanceForReceiver(this).StartCoroutine(PluginsMessageRoutine(jsonMsg)); 266 | } 267 | 268 | private IEnumerator PluginsMessageRoutine(JsonObject jsonMsg) 269 | { 270 | // this is to avoid a deadlock for more info when trying to get data from two separate native plugins and handling them in Unity 271 | yield return null; 272 | 273 | var msg = jsonMsg.GetString("msg"); 274 | if(msg.Equals(MSG_TEXT_BEGIN_EDIT)) 275 | { 276 | _isNowEditing = true; 277 | onBeginEdit?.Invoke(); 278 | } 279 | else if(msg.Equals(MSG_TEXT_CHANGE)) 280 | { 281 | inputField.text = jsonMsg.GetString("text"); 282 | } 283 | else if(msg.Equals(MSG_TEXT_END_EDIT)) 284 | { 285 | _isNowEditing = false; 286 | inputField.text = jsonMsg.GetString("text"); 287 | } 288 | else if(msg.Equals(MSG_RETURN_PRESSED)) 289 | { 290 | _isNowEditing = false; 291 | returnPressed?.Invoke(); 292 | onReturnPressed?.Invoke(); 293 | if(clearFocusOnReturnPressed) 294 | SetFocus(false); 295 | } 296 | } 297 | 298 | private bool CheckErrorJsonRet(JsonObject jsonRet) 299 | { 300 | var bError = jsonRet.GetBool("bError"); 301 | var strError = jsonRet.GetString("strError"); 302 | if(bError) Debug.LogError($"NativeEditbox error {strError}"); 303 | return bError; 304 | } 305 | 306 | private void CreateNativeEdit() 307 | { 308 | var rectScreen = GetScreenRectFromRectTransform(_textComponent.rectTransform); 309 | 310 | var jsonMsg = new JsonObject 311 | { 312 | ["msg"] = MSG_CREATE, 313 | ["x"] = rectScreen.x / Screen.width, 314 | ["y"] = rectScreen.y / Screen.height, 315 | ["width"] = rectScreen.width / Screen.width, 316 | ["height"] = rectScreen.height / Screen.height, 317 | ["characterLimit"] = _mConfig.characterLimit, 318 | ["textColor_r"] = _mConfig.textColor.r, 319 | ["textColor_g"] = _mConfig.textColor.g, 320 | ["textColor_b"] = _mConfig.textColor.b, 321 | ["textColor_a"] = _mConfig.textColor.a, 322 | ["backColor_r"] = _mConfig.backColor.r, 323 | ["backColor_g"] = _mConfig.backColor.g, 324 | ["backColor_b"] = _mConfig.backColor.b, 325 | ["backColor_a"] = _mConfig.backColor.a, 326 | ["font"] = _mConfig.font, 327 | ["fontSize"] = _mConfig.fontSize, 328 | ["contentType"] = _mConfig.contentType, 329 | ["align"] = _mConfig.align, 330 | ["withDoneButton"] = iOSWithDoneButton, 331 | ["placeHolder"] = _mConfig.placeHolder, 332 | ["placeHolderColor_r"] = _mConfig.placeHolderColor.r, 333 | ["placeHolderColor_g"] = _mConfig.placeHolderColor.g, 334 | ["placeHolderColor_b"] = _mConfig.placeHolderColor.b, 335 | ["placeHolderColor_a"] = _mConfig.placeHolderColor.a, 336 | ["multiline"] = _mConfig.multiline 337 | }; 338 | switch(singleLineReturnKeyType) 339 | { 340 | case ReturnKeyType.Next: 341 | jsonMsg["return_key_type"] = "Next"; 342 | break; 343 | case ReturnKeyType.Done: 344 | jsonMsg["return_key_type"] = "Done"; 345 | break; 346 | case ReturnKeyType.Send: 347 | jsonMsg["return_key_type"] = "Send"; 348 | break; 349 | case ReturnKeyType.Go: 350 | jsonMsg["return_key_type"] = "Go"; 351 | break; 352 | default: 353 | jsonMsg["return_key_type"] = "Default"; 354 | break; 355 | } 356 | 357 | var jsonRet = SendPluginMsg(jsonMsg); 358 | _hasNativeEditCreated = !CheckErrorJsonRet(jsonRet); 359 | 360 | visible = _visibleOnCreate; 361 | if(!_visibleOnCreate) 362 | SetVisible(false); 363 | 364 | if(_focusOnCreate) 365 | SetFocus(true); 366 | } 367 | 368 | private void SetTextNative(string newText) 369 | { 370 | var jsonMsg = new JsonObject 371 | { 372 | ["msg"] = MSG_SET_TEXT, 373 | ["text"] = newText ?? string.Empty 374 | }; 375 | SendPluginMsg(jsonMsg); 376 | } 377 | 378 | private void RemoveNative() 379 | { 380 | var jsonMsg = new JsonObject 381 | { 382 | ["msg"] = MSG_REMOVE 383 | }; 384 | SendPluginMsg(jsonMsg); 385 | } 386 | 387 | public void SetRectNative(RectTransform rectTrans) 388 | { 389 | var rectScreen = GetScreenRectFromRectTransform(rectTrans); 390 | var jsonMsg = new JsonObject 391 | { 392 | ["msg"] = MSG_SET_RECT, 393 | ["x"] = rectScreen.x / Screen.width, 394 | ["y"] = rectScreen.y / Screen.height, 395 | ["width"] = rectScreen.width / Screen.width, 396 | ["height"] = rectScreen.height / Screen.height 397 | }; 398 | SendPluginMsg(jsonMsg); 399 | } 400 | 401 | public void SetTextSize() 402 | { 403 | var fontSize = GetNativeFontSize(); 404 | if(Math.Abs(_mConfig.fontSize - fontSize) > 0.1f) 405 | { 406 | var sizeMsg = new JsonObject 407 | { 408 | ["msg"] = MSG_SET_TEXTSIZE, 409 | ["fontSize"] = fontSize 410 | }; 411 | SendPluginMsg(sizeMsg); 412 | _mConfig.fontSize = fontSize; 413 | } 414 | } 415 | 416 | public void SetFocus(bool bFocus) 417 | { 418 | #if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR 419 | if (!_hasNativeEditCreated) 420 | { 421 | _focusOnCreate = bFocus; 422 | return; 423 | } 424 | 425 | var jsonMsg = new JsonObject 426 | { 427 | ["msg"] = MSG_SET_FOCUS, 428 | ["isFocus"] = bFocus 429 | }; 430 | SendPluginMsg(jsonMsg); 431 | #else 432 | if(gameObject.activeInHierarchy) 433 | { 434 | if(bFocus) 435 | inputField.ActivateInputField(); 436 | else 437 | inputField.DeactivateInputField(); 438 | } 439 | else 440 | { 441 | _focusOnCreate = bFocus; 442 | } 443 | #endif 444 | } 445 | 446 | public void SetVisible(bool bVisible) 447 | { 448 | if(!_hasNativeEditCreated) 449 | { 450 | _visibleOnCreate = bVisible; 451 | return; 452 | } 453 | 454 | var jsonMsg = new JsonObject 455 | { 456 | ["msg"] = MSG_SET_VISIBLE, 457 | ["isVisible"] = bVisible 458 | }; 459 | SendPluginMsg(jsonMsg); 460 | 461 | visible = bVisible; 462 | } 463 | 464 | #if UNITY_ANDROID && !UNITY_EDITOR 465 | private void ForceSendKeydown_Android(string key) 466 | { 467 | var jsonMsg = new JsonObject 468 | { 469 | ["msg"] = MSG_ANDROID_KEY_DOWN, 470 | ["key"] = key 471 | }; 472 | SendPluginMsg(jsonMsg); 473 | } 474 | 475 | private void UpdateForceKeyeventForAndroid() 476 | { 477 | if (Input.anyKeyDown) 478 | { 479 | if (Input.GetKeyDown(KeyCode.Backspace)) 480 | { 481 | ForceSendKeydown_Android("backspace"); 482 | } 483 | else 484 | { 485 | foreach(char c in Input.inputString) 486 | { 487 | if (c == '\n') 488 | { 489 | ForceSendKeydown_Android("enter"); 490 | } 491 | else 492 | { 493 | ForceSendKeydown_Android(Input.inputString); 494 | } 495 | } 496 | } 497 | } 498 | } 499 | #endif 500 | } -------------------------------------------------------------------------------- /release/NativeEditPlugin/scripts/MiniJSON.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Calvin Rien 3 | * 4 | * Based on the JSON parser by Patrick van Bergen 5 | * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html 6 | * 7 | * Simplified it so that it doesn't throw exceptions 8 | * and can be used in Unity iPhone with maximum code stripping. 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining 11 | * a copy of this software and associated documentation files (the 12 | * "Software"), to deal in the Software without restriction, including 13 | * without limitation the rights to use, copy, modify, merge, publish, 14 | * distribute, sublicense, and/or sell copies of the Software, and to 15 | * permit persons to whom the Software is furnished to do so, subject to 16 | * the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 25 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | using System; 31 | using System.Collections; 32 | using System.Collections.Generic; 33 | using System.IO; 34 | using System.Text; 35 | 36 | namespace MiniJSON_Min 37 | { 38 | // Example usage: 39 | // 40 | // using UnityEngine; 41 | // using System.Collections; 42 | // using System.Collections.Generic; 43 | // using MiniJSON; 44 | // 45 | // public class MiniJSONTest : MonoBehaviour { 46 | // void Start () { 47 | // var jsonString = "{ \"array\": [1.44,2,3], " + 48 | // "\"object\": {\"key1\":\"value1\", \"key2\":256}, " + 49 | // "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " + 50 | // "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " + 51 | // "\"int\": 65536, " + 52 | // "\"float\": 3.1415926, " + 53 | // "\"bool\": true, " + 54 | // "\"null\": null }"; 55 | // 56 | // var dict = Json.Deserialize(jsonString) as Dictionary; 57 | // 58 | // Debug.Log("deserialized: " + dict.GetType()); 59 | // Debug.Log("dict['array'][0]: " + ((List) dict["array"])[0]); 60 | // Debug.Log("dict['string']: " + (string) dict["string"]); 61 | // Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles 62 | // Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs 63 | // Debug.Log("dict['unicode']: " + (string) dict["unicode"]); 64 | // 65 | // var str = Json.Serialize(dict); 66 | // 67 | // Debug.Log("serialized: " + str); 68 | // } 69 | // } 70 | 71 | /// 72 | /// This class encodes and decodes JSON strings. 73 | /// Spec. details, see http://www.json.org/ 74 | /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary. 75 | /// All numbers are parsed to doubles. 76 | /// 77 | public static class Json 78 | { 79 | /// 80 | /// Parses the string json into a value 81 | /// 82 | /// A JSON string. 83 | /// An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false 84 | public static object Deserialize(string json) 85 | { 86 | // save the string for debug information 87 | if(json == null) return null; 88 | 89 | return Parser.Parse(json); 90 | } 91 | 92 | /// 93 | /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string 94 | /// 95 | /// A Dictionary<string, object> / List<object> 96 | /// A JSON encoded string, or null if object 'json' is not serializable 97 | public static string Serialize(object obj) 98 | { 99 | return Serializer.Serialize(obj); 100 | } 101 | 102 | private sealed class Parser : IDisposable 103 | { 104 | private const string WHITE_SPACE = " \t\n\r"; 105 | private const string WORD_BREAK = " \t\n\r{}[],:\""; 106 | 107 | private StringReader json; 108 | 109 | private Parser(string jsonString) 110 | { 111 | json = new StringReader(jsonString); 112 | } 113 | 114 | private char PeekChar => Convert.ToChar(json.Peek()); 115 | 116 | private char NextChar => Convert.ToChar(json.Read()); 117 | 118 | private string NextWord 119 | { 120 | get 121 | { 122 | var word = new StringBuilder(); 123 | 124 | while(WORD_BREAK.IndexOf(PeekChar) == -1) 125 | { 126 | word.Append(NextChar); 127 | 128 | if(json.Peek() == -1) break; 129 | } 130 | 131 | return word.ToString(); 132 | } 133 | } 134 | 135 | private TOKEN NextToken 136 | { 137 | get 138 | { 139 | EatWhitespace(); 140 | 141 | if(json.Peek() == -1) return TOKEN.NONE; 142 | 143 | var c = PeekChar; 144 | switch(c) 145 | { 146 | case '{': 147 | return TOKEN.CURLY_OPEN; 148 | case '}': 149 | json.Read(); 150 | return TOKEN.CURLY_CLOSE; 151 | case '[': 152 | return TOKEN.SQUARED_OPEN; 153 | case ']': 154 | json.Read(); 155 | return TOKEN.SQUARED_CLOSE; 156 | case ',': 157 | json.Read(); 158 | return TOKEN.COMMA; 159 | case '"': 160 | return TOKEN.STRING; 161 | case ':': 162 | return TOKEN.COLON; 163 | case '0': 164 | case '1': 165 | case '2': 166 | case '3': 167 | case '4': 168 | case '5': 169 | case '6': 170 | case '7': 171 | case '8': 172 | case '9': 173 | case '-': 174 | return TOKEN.NUMBER; 175 | } 176 | 177 | var word = NextWord; 178 | 179 | switch(word) 180 | { 181 | case "false": 182 | return TOKEN.FALSE; 183 | case "true": 184 | return TOKEN.TRUE; 185 | case "null": 186 | return TOKEN.NULL; 187 | } 188 | 189 | return TOKEN.NONE; 190 | } 191 | } 192 | 193 | public void Dispose() 194 | { 195 | json.Dispose(); 196 | json = null; 197 | } 198 | 199 | public static object Parse(string jsonString) 200 | { 201 | using(var instance = new Parser(jsonString)) 202 | { 203 | return instance.ParseValue(); 204 | } 205 | } 206 | 207 | private Dictionary ParseObject() 208 | { 209 | var table = new Dictionary(); 210 | 211 | // ditch opening brace 212 | json.Read(); 213 | 214 | // { 215 | while(true) 216 | switch(NextToken) 217 | { 218 | case TOKEN.NONE: 219 | return null; 220 | case TOKEN.COMMA: 221 | continue; 222 | case TOKEN.CURLY_CLOSE: 223 | return table; 224 | default: 225 | // name 226 | var name = ParseString(); 227 | if(name == null) return null; 228 | 229 | // : 230 | if(NextToken != TOKEN.COLON) return null; 231 | // ditch the colon 232 | json.Read(); 233 | 234 | // value 235 | table[name] = ParseValue(); 236 | break; 237 | } 238 | } 239 | 240 | private List ParseArray() 241 | { 242 | var array = new List(); 243 | 244 | // ditch opening bracket 245 | json.Read(); 246 | 247 | // [ 248 | var parsing = true; 249 | while(parsing) 250 | { 251 | var nextToken = NextToken; 252 | 253 | switch(nextToken) 254 | { 255 | case TOKEN.NONE: 256 | return null; 257 | case TOKEN.COMMA: 258 | continue; 259 | case TOKEN.SQUARED_CLOSE: 260 | parsing = false; 261 | break; 262 | default: 263 | var value = ParseByToken(nextToken); 264 | 265 | array.Add(value); 266 | break; 267 | } 268 | } 269 | 270 | return array; 271 | } 272 | 273 | private object ParseValue() 274 | { 275 | var nextToken = NextToken; 276 | return ParseByToken(nextToken); 277 | } 278 | 279 | private object ParseByToken(TOKEN token) 280 | { 281 | switch(token) 282 | { 283 | case TOKEN.STRING: 284 | return ParseString(); 285 | case TOKEN.NUMBER: 286 | return ParseNumber(); 287 | case TOKEN.CURLY_OPEN: 288 | return ParseObject(); 289 | case TOKEN.SQUARED_OPEN: 290 | return ParseArray(); 291 | case TOKEN.TRUE: 292 | return true; 293 | case TOKEN.FALSE: 294 | return false; 295 | case TOKEN.NULL: 296 | return null; 297 | default: 298 | return null; 299 | } 300 | } 301 | 302 | private string ParseString() 303 | { 304 | var s = new StringBuilder(); 305 | char c; 306 | 307 | // ditch opening quote 308 | json.Read(); 309 | 310 | var parsing = true; 311 | while(parsing) 312 | { 313 | if(json.Peek() == -1) 314 | { 315 | parsing = false; 316 | break; 317 | } 318 | 319 | c = NextChar; 320 | switch(c) 321 | { 322 | case '"': 323 | parsing = false; 324 | break; 325 | case '\\': 326 | if(json.Peek() == -1) 327 | { 328 | parsing = false; 329 | break; 330 | } 331 | 332 | c = NextChar; 333 | switch(c) 334 | { 335 | case '"': 336 | case '\\': 337 | case '/': 338 | s.Append(c); 339 | break; 340 | case 'b': 341 | s.Append('\b'); 342 | break; 343 | case 'f': 344 | s.Append('\f'); 345 | break; 346 | case 'n': 347 | s.Append('\n'); 348 | break; 349 | case 'r': 350 | s.Append('\r'); 351 | break; 352 | case 't': 353 | s.Append('\t'); 354 | break; 355 | case 'u': 356 | var hex = new StringBuilder(); 357 | 358 | for(var i = 0; i < 4; i++) hex.Append(NextChar); 359 | 360 | s.Append((char) Convert.ToInt32(hex.ToString(), 16)); 361 | break; 362 | } 363 | 364 | break; 365 | default: 366 | s.Append(c); 367 | break; 368 | } 369 | } 370 | 371 | return s.ToString(); 372 | } 373 | 374 | private object ParseNumber() 375 | { 376 | var number = NextWord; 377 | 378 | if(number.IndexOf('.') == -1) 379 | { 380 | int parsedInt; 381 | int.TryParse(number, out parsedInt); 382 | return parsedInt; 383 | } 384 | 385 | float parsedFloat; 386 | float.TryParse(number, out parsedFloat); 387 | return parsedFloat; 388 | } 389 | 390 | private void EatWhitespace() 391 | { 392 | while(WHITE_SPACE.IndexOf(PeekChar) != -1) 393 | { 394 | json.Read(); 395 | 396 | if(json.Peek() == -1) break; 397 | } 398 | } 399 | 400 | private enum TOKEN 401 | { 402 | NONE, 403 | CURLY_OPEN, 404 | CURLY_CLOSE, 405 | SQUARED_OPEN, 406 | SQUARED_CLOSE, 407 | COLON, 408 | COMMA, 409 | STRING, 410 | NUMBER, 411 | TRUE, 412 | FALSE, 413 | NULL 414 | } 415 | } 416 | 417 | private sealed class Serializer 418 | { 419 | private readonly StringBuilder builder; 420 | 421 | private Serializer() 422 | { 423 | builder = new StringBuilder(); 424 | } 425 | 426 | public static string Serialize(object obj) 427 | { 428 | var instance = new Serializer(); 429 | 430 | instance.SerializeValue(obj); 431 | 432 | return instance.builder.ToString(); 433 | } 434 | 435 | private void SerializeValue(object value) 436 | { 437 | IList asList; 438 | IDictionary asDict; 439 | string asStr; 440 | 441 | if(value == null) 442 | builder.Append("null"); 443 | else if((asStr = value as string) != null) 444 | SerializeString(asStr); 445 | else if(value is bool) 446 | builder.Append(value.ToString().ToLower()); 447 | else if((asList = value as IList) != null) 448 | SerializeArray(asList); 449 | else if((asDict = value as IDictionary) != null) 450 | SerializeObject(asDict); 451 | else if(value is char) 452 | SerializeString(value.ToString()); 453 | else 454 | SerializeOther(value); 455 | } 456 | 457 | private void SerializeObject(IDictionary obj) 458 | { 459 | var first = true; 460 | 461 | builder.Append('{'); 462 | 463 | foreach(var e in obj.Keys) 464 | { 465 | if(!first) builder.Append(','); 466 | 467 | SerializeString(e.ToString()); 468 | builder.Append(':'); 469 | 470 | SerializeValue(obj[e]); 471 | 472 | first = false; 473 | } 474 | 475 | builder.Append('}'); 476 | } 477 | 478 | private void SerializeArray(IList anArray) 479 | { 480 | builder.Append('['); 481 | 482 | var first = true; 483 | 484 | foreach(var obj in anArray) 485 | { 486 | if(!first) builder.Append(','); 487 | 488 | SerializeValue(obj); 489 | 490 | first = false; 491 | } 492 | 493 | builder.Append(']'); 494 | } 495 | 496 | private void SerializeString(string str) 497 | { 498 | builder.Append('\"'); 499 | 500 | var charArray = str.ToCharArray(); 501 | foreach(var c in charArray) 502 | switch(c) 503 | { 504 | case '"': 505 | builder.Append("\\\""); 506 | break; 507 | case '\\': 508 | builder.Append("\\\\"); 509 | break; 510 | case '\b': 511 | builder.Append("\\b"); 512 | break; 513 | case '\f': 514 | builder.Append("\\f"); 515 | break; 516 | case '\n': 517 | builder.Append("\\n"); 518 | break; 519 | case '\r': 520 | builder.Append("\\r"); 521 | break; 522 | case '\t': 523 | builder.Append("\\t"); 524 | break; 525 | default: 526 | var codepoint = Convert.ToInt32(c); 527 | if(codepoint >= 32 && codepoint <= 126) 528 | builder.Append(c); 529 | else 530 | builder.Append("\\u" + Convert.ToString(codepoint, 16).PadLeft(4, '0')); 531 | break; 532 | } 533 | 534 | builder.Append('\"'); 535 | } 536 | 537 | private void SerializeOther(object value) 538 | { 539 | if(value is float 540 | || value is int 541 | || value is uint 542 | || value is long 543 | || value is double 544 | || value is sbyte 545 | || value is byte 546 | || value is short 547 | || value is ushort 548 | || value is ulong 549 | || value is decimal) 550 | builder.Append(value); 551 | else 552 | SerializeString(value.ToString()); 553 | } 554 | } 555 | } 556 | } -------------------------------------------------------------------------------- /release/NativeEditPlugin/Plugins/iOS/EditBox_iOS.m: -------------------------------------------------------------------------------- 1 | #import "EditBox_iOS.h" 2 | #import "PlaceholderTextView.h" 3 | #import 4 | 5 | /// UnityEditBox Plugin 6 | /// Written by bkmin 2014/11 Nureka Inc. 7 | 8 | //"Send" and "Go" return button support 9 | //move the whole view on keyboard showing/hiding 10 | //text alignment setting for TextView/TextField 11 | //call onTextEditEnd on keyboard hiding 12 | //fix bug "cannot use multi-touch" 13 | //UITapGestureRecognizer fixed for stripe zone on the left cannot respond on iPhone with 3DTouch 14 | 15 | UIViewController* unityViewController = nil; 16 | NSMutableDictionary* editBoxDict = nil; 17 | UITapGestureRecognizer* tapRecognizer = nil; 18 | 19 | char g_unityName[64]; 20 | 21 | bool approxEqualFloat(float x, float y) 22 | { 23 | return fabs(x-y) < 0.001f; 24 | } 25 | 26 | @implementation EditBox 27 | 28 | +(void) initializeEditBox:(UIViewController*) _unityViewController unityName:(const char*) unityName 29 | { 30 | unityViewController = _unityViewController; 31 | editBoxDict = [[NSMutableDictionary alloc] init]; 32 | strcpy(g_unityName, unityName); 33 | } 34 | 35 | +(JsonObject*) makeJsonRet:(BOOL) isError error:(NSString*) strError 36 | { 37 | JsonObject* jsonRet = [[JsonObject alloc] init]; 38 | 39 | [jsonRet setBool:@"bError" value:isError]; 40 | [jsonRet setString:@"strError" value:strError]; 41 | return jsonRet; 42 | } 43 | 44 | +(JsonObject*) processRecvJsonMsg:(int)nSenderId msg:(JsonObject*) jsonMsg 45 | { 46 | JsonObject* jsonRet; 47 | 48 | NSString* msg = [jsonMsg getString:@"msg"]; 49 | if ([msg isEqualToString:MSG_CREATE]) 50 | { 51 | EditBox* eb = [[EditBox alloc] initWithViewController:unityViewController _tag:nSenderId]; 52 | [eb create:jsonMsg]; 53 | [editBoxDict setObject:eb forKey:[NSNumber numberWithInt:nSenderId]]; 54 | jsonRet = [EditBox makeJsonRet:NO error:@""]; 55 | } 56 | else 57 | { 58 | EditBox* eb = [editBoxDict objectForKey:[NSNumber numberWithInt:nSenderId]]; 59 | if (eb) 60 | { 61 | jsonRet = [eb processJsonMsg:msg json:jsonMsg]; 62 | } 63 | else 64 | { 65 | jsonRet = [EditBox makeJsonRet:YES error:@"EditBox not found"]; 66 | } 67 | } 68 | return jsonRet; 69 | } 70 | 71 | +(void) finalizeEditBox 72 | { 73 | NSArray* objs = [editBoxDict allValues]; 74 | for (EditBox* eb in objs) 75 | { 76 | [eb remove]; 77 | } 78 | editBoxDict = nil; 79 | } 80 | 81 | -(void) sendJsonToUnity:(JsonObject*) json 82 | { 83 | [json setInt:@"senderId" value:tag]; 84 | 85 | 86 | NSData *jsonData = [json serialize]; 87 | NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 88 | UnitySendMessage(g_unityName, "OnMsgFromPlugin", [jsonString UTF8String]); 89 | } 90 | 91 | -(JsonObject*) processJsonMsg:(NSString*) msg json:(JsonObject*) jsonMsg 92 | { 93 | JsonObject* jsonRet = [EditBox makeJsonRet:NO error:@""]; 94 | if ([msg isEqualToString:MSG_REMOVE]) 95 | { 96 | [self remove]; 97 | } 98 | else if ([msg isEqualToString:MSG_SET_TEXT]) 99 | { 100 | [self setText:jsonMsg]; 101 | } 102 | else if ([msg isEqualToString:MSG_GET_TEXT]) 103 | { 104 | NSString* text = [self getText]; 105 | [jsonRet setString:@"text" value:text]; 106 | } 107 | else if ([msg isEqualToString:MSG_SET_RECT]) 108 | { 109 | [self setRect:jsonMsg]; 110 | } 111 | else if ([msg isEqualToString:MSG_SET_TEXTSIZE]) 112 | { 113 | [self setTextSize:jsonMsg]; 114 | } 115 | else if ([msg isEqualToString:MSG_SET_FOCUS]) 116 | { 117 | BOOL isFocus = [jsonMsg getBool:@"isFocus"]; 118 | [self setFocus:isFocus]; 119 | } 120 | else if ([msg isEqualToString:MSG_SET_VISIBLE]) 121 | { 122 | BOOL isVisible = [jsonMsg getBool:@"isVisible"]; 123 | [self setVisible:isVisible]; 124 | } 125 | 126 | return jsonRet; 127 | } 128 | 129 | -(id)initWithViewController:(UIViewController*)theViewController _tag:(int)_tag 130 | { 131 | if(self = [super init]) { 132 | viewController = theViewController; 133 | tag = _tag; 134 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; 135 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; 136 | } 137 | return self; 138 | } 139 | 140 | -(void) setRect:(JsonObject*)json 141 | { 142 | float x = [json getFloat:@"x"] * viewController.view.bounds.size.width; 143 | float y = [json getFloat:@"y"] * viewController.view.bounds.size.height; 144 | float width = [json getFloat:@"width"] * viewController.view.bounds.size.width; 145 | float height = [json getFloat:@"height"] * viewController.view.bounds.size.height; 146 | 147 | //x -= editView.superview.frame.origin.x; 148 | //y -= editView.superview.frame.origin.y; 149 | editView.frame = CGRectMake(x, y, width, height); 150 | } 151 | 152 | -(void) setTextSize:(JsonObject*)json 153 | { 154 | float fontSize = [json getFloat:@"fontSize"]; 155 | // Conversion for retina displays 156 | fontSize = fontSize / [UIScreen mainScreen].scale; 157 | 158 | if([editView isKindOfClass:[UITextField class]]) 159 | { 160 | UITextField *textField = ((UITextField*)editView); 161 | UIFont *newFont = [[textField font] fontWithSize:fontSize]; 162 | [textField setFont:newFont]; 163 | } 164 | else if([editView isKindOfClass:[UITextView class]]) 165 | { 166 | UITextView *textView = ((UITextView*)editView); 167 | UIFont *newFont = [[textView font] fontWithSize:fontSize]; 168 | [textView setFont:newFont]; 169 | } 170 | } 171 | 172 | -(void) create:(JsonObject*)json 173 | { 174 | NSString* placeholder = [json getString:@"placeHolder"]; 175 | 176 | NSString* font = [json getString:@"font"]; 177 | float fontSize = [json getFloat:@"fontSize"]; 178 | 179 | float x = [json getFloat:@"x"] * viewController.view.bounds.size.width; 180 | float y = [json getFloat:@"y"] * viewController.view.bounds.size.height; 181 | float width = [json getFloat:@"width"] * viewController.view.bounds.size.width; 182 | float height = [json getFloat:@"height"] * viewController.view.bounds.size.height; 183 | 184 | [self setMaxLength:[json getInt:@"characterLimit"]]; 185 | 186 | float textColor_r = [json getFloat:@"textColor_r"]; 187 | float textColor_g = [json getFloat:@"textColor_g"]; 188 | float textColor_b = [json getFloat:@"textColor_b"]; 189 | float textColor_a = [json getFloat:@"textColor_a"]; 190 | UIColor* textColor = [UIColor colorWithRed:textColor_r green:textColor_g blue:textColor_b alpha:textColor_a]; 191 | 192 | float backColor_r = [json getFloat:@"backColor_r"]; 193 | float backColor_g = [json getFloat:@"backColor_g"]; 194 | float backColor_b = [json getFloat:@"backColor_b"]; 195 | float backColor_a = [json getFloat:@"backColor_a"]; 196 | UIColor* backgroundColor = [UIColor colorWithRed:backColor_r green:backColor_g blue:backColor_b alpha:backColor_a]; 197 | 198 | float placeHolderColor_r = [json getFloat:@"placeHolderColor_r"]; 199 | float placeHolderColor_g = [json getFloat:@"placeHolderColor_g"]; 200 | float placeHolderColor_b = [json getFloat:@"placeHolderColor_b"]; 201 | float placeHolderColor_a = [json getFloat:@"placeHolderColor_a"]; 202 | UIColor* placeHolderColor = [UIColor colorWithRed:placeHolderColor_r green:placeHolderColor_g blue:placeHolderColor_b alpha:placeHolderColor_a]; 203 | 204 | NSString* contentType = [json getString:@"contentType"]; 205 | NSString* alignment = [json getString:@"align"]; 206 | BOOL withDoneButton = [json getBool:@"withDoneButton"]; 207 | BOOL multiline = [json getBool:@"multiline"]; 208 | 209 | BOOL autoCorr = NO; 210 | BOOL password = NO; 211 | UIKeyboardType keyType = UIKeyboardTypeDefault; 212 | 213 | if ([contentType isEqualToString:@"Autocorrected"]) 214 | { 215 | autoCorr = YES; 216 | } 217 | else if ([contentType isEqualToString:@"IntegerNumber"]) 218 | { 219 | keyType = UIKeyboardTypeNumberPad; 220 | } 221 | else if ([contentType isEqualToString:@"DecimalNumber"]) 222 | { 223 | keyType = UIKeyboardTypeDecimalPad; 224 | } 225 | else if ([contentType isEqualToString:@"Alphanumeric"]) 226 | { 227 | keyType = UIKeyboardTypeAlphabet; 228 | } 229 | else if ([contentType isEqualToString:@"Name"]) 230 | { 231 | keyType = UIKeyboardTypeNamePhonePad; 232 | } 233 | else if ([contentType isEqualToString:@"EmailAddress"]) 234 | { 235 | keyType = UIKeyboardTypeEmailAddress; 236 | } 237 | else if ([contentType isEqualToString:@"Password"]) 238 | { 239 | password = YES; 240 | } 241 | else if ([contentType isEqualToString:@"Pin"]) 242 | { 243 | keyType = UIKeyboardTypePhonePad; 244 | } 245 | 246 | NSTextAlignment textAlignment; 247 | if ([alignment isEqualToString:@"UpperLeft"]) 248 | { 249 | textAlignment = NSTextAlignmentLeft; 250 | } 251 | else if ([alignment isEqualToString:@"UpperCenter"]) 252 | { 253 | textAlignment = NSTextAlignmentCenter; 254 | } 255 | else if ([alignment isEqualToString:@"UpperRight"]) 256 | { 257 | textAlignment = NSTextAlignmentRight; 258 | } 259 | else if ([alignment isEqualToString:@"MiddleLeft"]) 260 | { 261 | textAlignment = NSTextAlignmentLeft; 262 | } 263 | else if ([alignment isEqualToString:@"MiddleCenter"]) 264 | { 265 | textAlignment = NSTextAlignmentCenter; 266 | } 267 | else if ([alignment isEqualToString:@"MiddleRight"]) 268 | { 269 | textAlignment = NSTextAlignmentRight; 270 | } 271 | else if ([alignment isEqualToString:@"LowerLeft"]) 272 | { 273 | textAlignment = NSTextAlignmentLeft; 274 | } 275 | else if ([alignment isEqualToString:@"LowerCenter"]) 276 | { 277 | textAlignment = NSTextAlignmentCenter; 278 | } 279 | else if ([alignment isEqualToString:@"LowerRight"]) 280 | { 281 | textAlignment = NSTextAlignmentRight; 282 | } 283 | 284 | if (withDoneButton) 285 | { 286 | keyboardDoneButtonView = [[UIToolbar alloc] init]; 287 | [keyboardDoneButtonView sizeToFit]; 288 | doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self 289 | action:@selector(doneClicked:)]; 290 | 291 | UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 292 | [keyboardDoneButtonView setItems:[NSArray arrayWithObjects:flexibleSpace, flexibleSpace,doneButton, nil]]; 293 | } 294 | else 295 | { 296 | keyboardDoneButtonView = nil; 297 | } 298 | 299 | UIReturnKeyType returnKeyType = UIReturnKeyDefault; 300 | NSString* returnKeyTypeString = [json getString:@"return_key_type"]; 301 | if ([returnKeyTypeString isEqualToString:@"Next"]) 302 | { 303 | returnKeyType = UIReturnKeyNext; 304 | } 305 | else if ([returnKeyTypeString isEqualToString:@"Done"]) 306 | { 307 | returnKeyType = UIReturnKeyDone; 308 | } 309 | else if ([returnKeyTypeString isEqualToString:@"Send"]) 310 | { 311 | returnKeyType = UIReturnKeySend; 312 | } 313 | else if ([returnKeyTypeString isEqualToString:@"Go"]) 314 | { 315 | returnKeyType = UIReturnKeyGo; 316 | } 317 | 318 | // Conversion for retina displays 319 | fontSize = fontSize / [UIScreen mainScreen].scale; 320 | 321 | UIFont* uiFont; 322 | if ([font length] > 0) 323 | { 324 | uiFont = [UIFont fontWithName:font size:fontSize]; 325 | } 326 | else 327 | { 328 | uiFont = [UIFont systemFontOfSize:fontSize]; 329 | } 330 | 331 | if (multiline) 332 | { 333 | PlaceholderTextView* textView = [[PlaceholderTextView alloc] initWithFrame:CGRectMake(x, y, width, height)]; 334 | textView.keyboardType = keyType; 335 | 336 | [textView setFont:uiFont]; 337 | 338 | textView.scrollEnabled = TRUE; 339 | 340 | textView.delegate = self; 341 | textView.tag = 0; 342 | textView.text = @""; 343 | 344 | textView.textColor = textColor; 345 | textView.backgroundColor = backgroundColor; 346 | textView.returnKeyType = returnKeyType; 347 | textView.textAlignment = textAlignment; 348 | textView.autocorrectionType = autoCorr ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo; 349 | textView.contentInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f); 350 | textView.placeholder = placeholder; 351 | textView.placeholderColor = placeHolderColor; 352 | textView.delegate = self; 353 | if (keyType == UIKeyboardTypeEmailAddress) 354 | textView.autocapitalizationType = UITextAutocapitalizationTypeNone; 355 | 356 | [textView setSecureTextEntry:password]; 357 | if (keyboardDoneButtonView != nil) textView.inputAccessoryView = keyboardDoneButtonView; 358 | 359 | editView = textView; 360 | } 361 | else 362 | { 363 | UITextField* textField = [[UITextField alloc] initWithFrame:CGRectMake(x, y, width, height)]; 364 | textField.keyboardType = keyType; 365 | [textField setFont:uiFont]; 366 | textField.delegate = self; 367 | textField.tag = 0; 368 | textField.text = @""; 369 | textField.textColor = textColor; 370 | textField.backgroundColor = backgroundColor; 371 | textField.returnKeyType = returnKeyType; 372 | textField.autocorrectionType = autoCorr ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo; 373 | textField.textAlignment = textAlignment; 374 | // Settings the placeholder like this is needed because otherwise it will not be visible 375 | textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:placeholder attributes:@{NSForegroundColorAttributeName: placeHolderColor}]; 376 | textField.delegate = self; 377 | if (keyType == UIKeyboardTypeEmailAddress) 378 | textField.autocapitalizationType = UITextAutocapitalizationTypeNone; 379 | 380 | [textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; 381 | [textField setSecureTextEntry:password]; 382 | if (keyboardDoneButtonView != nil) textField.inputAccessoryView = keyboardDoneButtonView; 383 | 384 | editView = textField; 385 | } 386 | [unityViewController.view addSubview:editView]; 387 | } 388 | 389 | -(void) setText:(JsonObject*)json 390 | { 391 | NSString* newText = [json getString:@"text"]; 392 | if([editView isKindOfClass:[UITextField class]]) { 393 | [((UITextField*)editView) setText:newText]; 394 | } else if([editView isKindOfClass:[UITextView class]]){ 395 | [((UITextView*)editView) setText:newText]; 396 | } 397 | } 398 | 399 | -(IBAction) doneClicked:(id)sender 400 | { 401 | [self hideKeyboard]; 402 | } 403 | 404 | -(int) getLineCount 405 | { 406 | if([editView isKindOfClass:[UITextField class]]) { 407 | return 1; 408 | } else if([editView isKindOfClass:[UITextView class]]){ 409 | UITextView* tv = ((UITextView*)editView); 410 | int lineCount = (int) tv.contentSize.height / tv.font.lineHeight; 411 | return (lineCount); 412 | } 413 | return 0; 414 | } 415 | 416 | 417 | -(void) remove 418 | { 419 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 420 | [editView resignFirstResponder]; 421 | [editView removeFromSuperview]; 422 | if (keyboardDoneButtonView != nil) 423 | { 424 | doneButton = nil; 425 | keyboardDoneButtonView = nil; 426 | } 427 | } 428 | 429 | -(void) setFocus:(BOOL) isFocus 430 | { 431 | if (isFocus) 432 | { 433 | [editView becomeFirstResponder]; 434 | } 435 | else 436 | { 437 | [editView resignFirstResponder]; 438 | } 439 | } 440 | 441 | -(NSString*) getText 442 | { 443 | if([editView isKindOfClass:[UITextField class]]) { 444 | return ((UITextField*)editView).text; 445 | } else if([editView isKindOfClass:[UITextView class]]){ 446 | return ((UITextView*)editView).text; 447 | } 448 | return @""; 449 | } 450 | 451 | -(void) hideKeyboard 452 | { 453 | [editView resignFirstResponder]; 454 | } 455 | 456 | -(void) setVisible:(bool)isVisible 457 | { 458 | editView.hidden = !isVisible; 459 | } 460 | 461 | -(void) onTextChange:(NSString*) text 462 | { 463 | JsonObject* jsonToUnity = [[JsonObject alloc] init]; 464 | 465 | [jsonToUnity setString:@"msg" value:MSG_TEXT_CHANGE]; 466 | [jsonToUnity setString:@"text" value:text]; 467 | [self sendJsonToUnity:jsonToUnity]; 468 | } 469 | 470 | -(void) onTextEditBegin 471 | { 472 | JsonObject* jsonToUnity = [[JsonObject alloc] init]; 473 | 474 | [jsonToUnity setString:@"msg" value:MSG_TEXT_BEGIN_EDIT]; 475 | [self sendJsonToUnity:jsonToUnity]; 476 | } 477 | 478 | -(void) onTextEditEnd:(NSString*) text 479 | { 480 | JsonObject* jsonToUnity = [[JsonObject alloc] init]; 481 | 482 | [jsonToUnity setString:@"msg" value:MSG_TEXT_END_EDIT]; 483 | [jsonToUnity setString:@"text" value:text]; 484 | [self sendJsonToUnity:jsonToUnity]; 485 | } 486 | 487 | -(void) textViewDidBeginEditing:(UITextView *)textView 488 | { 489 | [self onTextEditBegin]; 490 | } 491 | 492 | -(void) textViewDidEndEditing:(UITextView *)textView 493 | { 494 | [self onTextEditEnd:textView.text]; 495 | } 496 | 497 | -(void) textViewDidChange:(UITextView *)textView 498 | { 499 | [self onTextChange:textView.text]; 500 | } 501 | 502 | -(void) textFieldDidBeginEditing:(UITextField *)textField 503 | { 504 | [self onTextEditBegin]; 505 | } 506 | 507 | -(void) textFieldDidEndEditing:(UITextField *)textField 508 | { 509 | [self onTextEditEnd:textField.text]; 510 | } 511 | 512 | - (BOOL)textFieldShouldReturn:(UITextField *)textField 513 | { 514 | if (![editView isFirstResponder]) return YES; 515 | JsonObject* jsonToUnity = [[JsonObject alloc] init]; 516 | 517 | [jsonToUnity setString:@"msg" value:MSG_RETURN_PRESSED]; 518 | [self sendJsonToUnity:jsonToUnity]; 519 | return YES; 520 | } 521 | 522 | - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { 523 | // Prevent crashing undo bug – see note below. 524 | if(range.length + range.location > textField.text.length) 525 | { 526 | return NO; 527 | } 528 | 529 | NSUInteger newLength = [textField.text length] + [string length] - range.length; 530 | if([self maxLength] > 0) 531 | return newLength <= [self maxLength]; 532 | else 533 | return YES; 534 | } 535 | 536 | -(void) textFieldDidChange :(UITextField *)theTextField{ 537 | [self onTextChange:theTextField.text]; 538 | } 539 | 540 | -(void) keyboardWillShow:(NSNotification *)notification 541 | { 542 | if (![editView isFirstResponder]) return; 543 | 544 | //get keyboard height 545 | CGFloat kbHeight = [[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; 546 | //calculate the distance from the top of keyboard to the bottom of TextView/TextField 547 | CGFloat offset = (editView.frame.origin.y + editView.frame.size.height) - (unityViewController.view.frame.size.height - kbHeight); 548 | //get the duration of keyboard showing animation 549 | double duration = [[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; 550 | //move the whole view 551 | if (offset > 0){ 552 | [UIView animateWithDuration:duration animations:^{ 553 | unityViewController.view.frame = CGRectMake(0, -offset, unityViewController.view.frame.size.width, unityViewController.view.frame.size.height); 554 | }]; 555 | } 556 | 557 | //add tapRecognizer on keyboard showing 558 | if (tapRecognizer == nil){ 559 | tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)]; 560 | [unityViewController.view addGestureRecognizer:tapRecognizer]; 561 | } 562 | } 563 | 564 | -(void) keyboardWillHide:(NSNotification*)notification 565 | { 566 | if (![editView isFirstResponder]) return; 567 | 568 | //get the duration of keyboard hiding animation 569 | double duration = [[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; 570 | //move the whole view 571 | [UIView animateWithDuration:duration animations:^{ 572 | unityViewController.view.frame = CGRectMake(0, 0, unityViewController.view.frame.size.width, unityViewController.view.frame.size.height); 573 | }]; 574 | 575 | //remove tapRecognizer on keyboard hiding 576 | if (tapRecognizer != nil){ 577 | [unityViewController.view removeGestureRecognizer:tapRecognizer]; 578 | tapRecognizer = nil; 579 | } 580 | 581 | //call onTextEditEnd 582 | if ([editView isKindOfClass:[UITextView class]]){ 583 | UITextView* textView = (UITextView*) editView; 584 | [self onTextEditEnd:textView.text]; 585 | } else if ([editView isKindOfClass:[UITextField class]]){ 586 | UITextField* textField = (UITextField*) editView; 587 | [self onTextEditEnd:textField.text]; 588 | } 589 | } 590 | 591 | -(BOOL) isFocused 592 | { 593 | return editView.isFirstResponder; 594 | } 595 | 596 | -(void) tapAction:(id) sender 597 | { 598 | for (EditBox *eb in [editBoxDict allValues]) 599 | { 600 | if ([eb isFocused]) 601 | { 602 | [eb hideKeyboard]; 603 | } 604 | } 605 | } 606 | 607 | @end 608 | -------------------------------------------------------------------------------- /demo/ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!129 &1 4 | PlayerSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 14 7 | productGUID: 7b1f4714c2bff4320a429e8ac6727693 8 | AndroidProfiler: 0 9 | AndroidFilterTouchesWhenObscured: 0 10 | defaultScreenOrientation: 4 11 | targetDevice: 2 12 | useOnDemandResources: 0 13 | accelerometerFrequency: 60 14 | companyName: Indeegogames 15 | productName: nativeedit 16 | defaultCursor: {fileID: 0} 17 | cursorHotspot: {x: 0, y: 0} 18 | m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} 19 | m_ShowUnitySplashScreen: 1 20 | m_ShowUnitySplashLogo: 1 21 | m_SplashScreenOverlayOpacity: 1 22 | m_SplashScreenAnimation: 1 23 | m_SplashScreenLogoStyle: 1 24 | m_SplashScreenDrawMode: 0 25 | m_SplashScreenBackgroundAnimationZoom: 1 26 | m_SplashScreenLogoAnimationZoom: 1 27 | m_SplashScreenBackgroundLandscapeAspect: 1 28 | m_SplashScreenBackgroundPortraitAspect: 1 29 | m_SplashScreenBackgroundLandscapeUvs: 30 | serializedVersion: 2 31 | x: 0 32 | y: 0 33 | width: 1 34 | height: 1 35 | m_SplashScreenBackgroundPortraitUvs: 36 | serializedVersion: 2 37 | x: 0 38 | y: 0 39 | width: 1 40 | height: 1 41 | m_SplashScreenLogos: [] 42 | m_VirtualRealitySplashScreen: {fileID: 0} 43 | m_HolographicTrackingLossScreen: {fileID: 0} 44 | defaultScreenWidth: 1024 45 | defaultScreenHeight: 768 46 | defaultScreenWidthWeb: 960 47 | defaultScreenHeightWeb: 600 48 | m_StereoRenderingPath: 0 49 | m_ActiveColorSpace: 0 50 | m_MTRendering: 1 51 | m_StackTraceTypes: 010000000100000001000000010000000100000001000000 52 | iosShowActivityIndicatorOnLoading: -1 53 | androidShowActivityIndicatorOnLoading: -1 54 | tizenShowActivityIndicatorOnLoading: -1 55 | iosAppInBackgroundBehavior: 0 56 | displayResolutionDialog: 1 57 | iosAllowHTTPDownload: 1 58 | allowedAutorotateToPortrait: 0 59 | allowedAutorotateToPortraitUpsideDown: 0 60 | allowedAutorotateToLandscapeRight: 1 61 | allowedAutorotateToLandscapeLeft: 1 62 | useOSAutorotation: 1 63 | use32BitDisplayBuffer: 1 64 | preserveFramebufferAlpha: 0 65 | disableDepthAndStencilBuffers: 0 66 | androidBlitType: 0 67 | defaultIsFullScreen: 1 68 | defaultIsNativeResolution: 1 69 | macRetinaSupport: 1 70 | runInBackground: 1 71 | captureSingleScreen: 0 72 | muteOtherAudioSources: 0 73 | Prepare IOS For Recording: 0 74 | Force IOS Speakers When Recording: 0 75 | deferSystemGesturesMode: 0 76 | hideHomeButton: 0 77 | submitAnalytics: 1 78 | usePlayerLog: 1 79 | bakeCollisionMeshes: 0 80 | forceSingleInstance: 0 81 | resizableWindow: 0 82 | useMacAppStoreValidation: 0 83 | macAppStoreCategory: public.app-category.games 84 | gpuSkinning: 0 85 | graphicsJobs: 0 86 | xboxPIXTextureCapture: 0 87 | xboxEnableAvatar: 0 88 | xboxEnableKinect: 0 89 | xboxEnableKinectAutoTracking: 0 90 | xboxEnableFitness: 0 91 | visibleInBackground: 0 92 | allowFullscreenSwitch: 1 93 | graphicsJobMode: 0 94 | macFullscreenMode: 2 95 | d3d11FullscreenMode: 1 96 | xboxSpeechDB: 0 97 | xboxEnableHeadOrientation: 0 98 | xboxEnableGuest: 0 99 | xboxEnablePIXSampling: 0 100 | metalFramebufferOnly: 0 101 | n3dsDisableStereoscopicView: 0 102 | n3dsEnableSharedListOpt: 1 103 | n3dsEnableVSync: 0 104 | xboxOneResolution: 0 105 | xboxOneSResolution: 0 106 | xboxOneXResolution: 3 107 | xboxOneMonoLoggingLevel: 0 108 | xboxOneLoggingLevel: 1 109 | xboxOneDisableEsram: 0 110 | xboxOnePresentImmediateThreshold: 0 111 | videoMemoryForVertexBuffers: 0 112 | psp2PowerMode: 0 113 | psp2AcquireBGM: 1 114 | wiiUTVResolution: 0 115 | wiiUGamePadMSAA: 1 116 | wiiUSupportsNunchuk: 0 117 | wiiUSupportsClassicController: 0 118 | wiiUSupportsBalanceBoard: 0 119 | wiiUSupportsMotionPlus: 0 120 | wiiUSupportsProController: 0 121 | wiiUAllowScreenCapture: 1 122 | wiiUControllerCount: 0 123 | m_SupportedAspectRatios: 124 | 4:3: 1 125 | 5:4: 1 126 | 16:10: 1 127 | 16:9: 1 128 | Others: 1 129 | bundleVersion: 1.0 130 | preloadedAssets: [] 131 | metroInputSource: 0 132 | wsaTransparentSwapchain: 0 133 | m_HolographicPauseOnTrackingLoss: 1 134 | xboxOneDisableKinectGpuReservation: 0 135 | xboxOneEnable7thCore: 0 136 | vrSettings: 137 | cardboard: 138 | depthFormat: 0 139 | enableTransitionView: 0 140 | daydream: 141 | depthFormat: 0 142 | useSustainedPerformanceMode: 0 143 | enableVideoLayer: 0 144 | useProtectedVideoMemory: 0 145 | minimumSupportedHeadTracking: 0 146 | maximumSupportedHeadTracking: 1 147 | hololens: 148 | depthFormat: 1 149 | depthBufferSharingEnabled: 0 150 | oculus: 151 | sharedDepthBuffer: 0 152 | dashSupport: 0 153 | protectGraphicsMemory: 0 154 | useHDRDisplay: 0 155 | m_ColorGamuts: 00000000 156 | targetPixelDensity: 30 157 | resolutionScalingMode: 0 158 | androidSupportedAspectRatio: 1 159 | androidMaxAspectRatio: 2.1 160 | applicationIdentifier: 161 | Android: com.indeegogames.nativeedit 162 | Standalone: unity.Indeegogames.nativeedit 163 | Tizen: com.indeegogames.nativeedit 164 | iOS: com.indeegogames.nativeedit 165 | tvOS: com.indeegogames.nativeedit 166 | buildNumber: 167 | iOS: 0 168 | AndroidBundleVersionCode: 1 169 | AndroidMinSdkVersion: 19 170 | AndroidTargetSdkVersion: 0 171 | AndroidPreferredInstallLocation: 1 172 | aotOptions: 173 | stripEngineCode: 1 174 | iPhoneStrippingLevel: 0 175 | iPhoneScriptCallOptimization: 0 176 | ForceInternetPermission: 0 177 | ForceSDCardPermission: 0 178 | CreateWallpaper: 0 179 | APKExpansionFiles: 0 180 | keepLoadedShadersAlive: 0 181 | StripUnusedMeshComponents: 0 182 | VertexChannelCompressionMask: 183 | serializedVersion: 2 184 | m_Bits: 238 185 | iPhoneSdkVersion: 988 186 | iOSTargetOSVersionString: 7.0 187 | tvOSSdkVersion: 0 188 | tvOSRequireExtendedGameController: 0 189 | tvOSTargetOSVersionString: 9.0 190 | uIPrerenderedIcon: 0 191 | uIRequiresPersistentWiFi: 0 192 | uIRequiresFullScreen: 1 193 | uIStatusBarHidden: 1 194 | uIExitOnSuspend: 0 195 | uIStatusBarStyle: 0 196 | iPhoneSplashScreen: {fileID: 0} 197 | iPhoneHighResSplashScreen: {fileID: 0} 198 | iPhoneTallHighResSplashScreen: {fileID: 0} 199 | iPhone47inSplashScreen: {fileID: 0} 200 | iPhone55inPortraitSplashScreen: {fileID: 0} 201 | iPhone55inLandscapeSplashScreen: {fileID: 0} 202 | iPhone58inPortraitSplashScreen: {fileID: 0} 203 | iPhone58inLandscapeSplashScreen: {fileID: 0} 204 | iPadPortraitSplashScreen: {fileID: 0} 205 | iPadHighResPortraitSplashScreen: {fileID: 0} 206 | iPadLandscapeSplashScreen: {fileID: 0} 207 | iPadHighResLandscapeSplashScreen: {fileID: 0} 208 | appleTVSplashScreen: {fileID: 0} 209 | appleTVSplashScreen2x: {fileID: 0} 210 | tvOSSmallIconLayers: [] 211 | tvOSSmallIconLayers2x: [] 212 | tvOSLargeIconLayers: [] 213 | tvOSTopShelfImageLayers: [] 214 | tvOSTopShelfImageLayers2x: [] 215 | tvOSTopShelfImageWideLayers: [] 216 | tvOSTopShelfImageWideLayers2x: [] 217 | iOSLaunchScreenType: 0 218 | iOSLaunchScreenPortrait: {fileID: 0} 219 | iOSLaunchScreenLandscape: {fileID: 0} 220 | iOSLaunchScreenBackgroundColor: 221 | serializedVersion: 2 222 | rgba: 0 223 | iOSLaunchScreenFillPct: 1 224 | iOSLaunchScreenSize: 100 225 | iOSLaunchScreenCustomXibPath: 226 | iOSLaunchScreeniPadType: 0 227 | iOSLaunchScreeniPadImage: {fileID: 0} 228 | iOSLaunchScreeniPadBackgroundColor: 229 | serializedVersion: 2 230 | rgba: 0 231 | iOSLaunchScreeniPadFillPct: 100 232 | iOSLaunchScreeniPadSize: 100 233 | iOSLaunchScreeniPadCustomXibPath: 234 | iOSUseLaunchScreenStoryboard: 0 235 | iOSLaunchScreenCustomStoryboardPath: 236 | iOSDeviceRequirements: [] 237 | iOSURLSchemes: [] 238 | iOSBackgroundModes: 0 239 | iOSMetalForceHardShadows: 0 240 | metalEditorSupport: 0 241 | metalAPIValidation: 1 242 | iOSRenderExtraFrameOnPause: 1 243 | appleDeveloperTeamID: 244 | iOSManualSigningProvisioningProfileID: 245 | tvOSManualSigningProvisioningProfileID: 246 | appleEnableAutomaticSigning: 0 247 | clonedFromGUID: 00000000000000000000000000000000 248 | AndroidTargetDevice: 0 249 | AndroidSplashScreenScale: 0 250 | androidSplashScreen: {fileID: 0} 251 | AndroidKeystoreName: 252 | AndroidKeyaliasName: 253 | AndroidTVCompatibility: 1 254 | AndroidIsGame: 1 255 | AndroidEnableTango: 0 256 | androidEnableBanner: 1 257 | androidUseLowAccuracyLocation: 0 258 | m_AndroidBanners: 259 | - width: 320 260 | height: 180 261 | banner: {fileID: 0} 262 | androidGamepadSupportLevel: 0 263 | resolutionDialogBanner: {fileID: 0} 264 | m_BuildTargetIcons: 265 | - m_BuildTarget: 266 | m_Icons: 267 | - serializedVersion: 2 268 | m_Icon: {fileID: 0} 269 | m_Width: 128 270 | m_Height: 128 271 | m_Kind: 13154 272 | m_BuildTargetBatching: [] 273 | m_BuildTargetGraphicsAPIs: [] 274 | m_BuildTargetVRSettings: 275 | - m_BuildTarget: Android 276 | m_Enabled: 0 277 | m_Devices: 278 | - Oculus 279 | - m_BuildTarget: Metro 280 | m_Enabled: 0 281 | m_Devices: [] 282 | - m_BuildTarget: N3DS 283 | m_Enabled: 0 284 | m_Devices: [] 285 | - m_BuildTarget: PS3 286 | m_Enabled: 0 287 | m_Devices: [] 288 | - m_BuildTarget: PS4 289 | m_Enabled: 0 290 | m_Devices: 291 | - PlayStationVR 292 | - m_BuildTarget: PSM 293 | m_Enabled: 0 294 | m_Devices: [] 295 | - m_BuildTarget: PSP2 296 | m_Enabled: 0 297 | m_Devices: [] 298 | - m_BuildTarget: SamsungTV 299 | m_Enabled: 0 300 | m_Devices: [] 301 | - m_BuildTarget: Standalone 302 | m_Enabled: 0 303 | m_Devices: 304 | - Oculus 305 | - m_BuildTarget: Tizen 306 | m_Enabled: 0 307 | m_Devices: [] 308 | - m_BuildTarget: WebGL 309 | m_Enabled: 0 310 | m_Devices: [] 311 | - m_BuildTarget: WebPlayer 312 | m_Enabled: 0 313 | m_Devices: [] 314 | - m_BuildTarget: WiiU 315 | m_Enabled: 0 316 | m_Devices: [] 317 | - m_BuildTarget: Xbox360 318 | m_Enabled: 0 319 | m_Devices: [] 320 | - m_BuildTarget: XboxOne 321 | m_Enabled: 0 322 | m_Devices: [] 323 | - m_BuildTarget: iOS 324 | m_Enabled: 0 325 | m_Devices: [] 326 | - m_BuildTarget: tvOS 327 | m_Enabled: 0 328 | m_Devices: [] 329 | m_BuildTargetEnableVuforiaSettings: [] 330 | openGLRequireES31: 0 331 | openGLRequireES31AEP: 0 332 | m_TemplateCustomTags: {} 333 | mobileMTRendering: 334 | iPhone: 1 335 | tvOS: 1 336 | m_BuildTargetGroupLightmapEncodingQuality: 337 | - m_BuildTarget: Standalone 338 | m_EncodingQuality: 1 339 | - m_BuildTarget: XboxOne 340 | m_EncodingQuality: 1 341 | - m_BuildTarget: PS4 342 | m_EncodingQuality: 1 343 | wiiUTitleID: 0005000011000000 344 | wiiUGroupID: 00010000 345 | wiiUCommonSaveSize: 4096 346 | wiiUAccountSaveSize: 2048 347 | wiiUOlvAccessKey: 0 348 | wiiUTinCode: 0 349 | wiiUJoinGameId: 0 350 | wiiUJoinGameModeMask: 0000000000000000 351 | wiiUCommonBossSize: 0 352 | wiiUAccountBossSize: 0 353 | wiiUAddOnUniqueIDs: [] 354 | wiiUMainThreadStackSize: 3072 355 | wiiULoaderThreadStackSize: 1024 356 | wiiUSystemHeapSize: 128 357 | wiiUTVStartupScreen: {fileID: 0} 358 | wiiUGamePadStartupScreen: {fileID: 0} 359 | wiiUDrcBufferDisabled: 0 360 | wiiUProfilerLibPath: 361 | playModeTestRunnerEnabled: 0 362 | actionOnDotNetUnhandledException: 1 363 | enableInternalProfiler: 0 364 | logObjCUncaughtExceptions: 1 365 | enableCrashReportAPI: 0 366 | cameraUsageDescription: 367 | locationUsageDescription: 368 | microphoneUsageDescription: 369 | switchNetLibKey: 370 | switchSocketMemoryPoolSize: 6144 371 | switchSocketAllocatorPoolSize: 128 372 | switchSocketConcurrencyLimit: 14 373 | switchScreenResolutionBehavior: 2 374 | switchUseCPUProfiler: 0 375 | switchApplicationID: 0x0005000C10000001 376 | switchNSODependencies: 377 | switchTitleNames_0: 378 | switchTitleNames_1: 379 | switchTitleNames_2: 380 | switchTitleNames_3: 381 | switchTitleNames_4: 382 | switchTitleNames_5: 383 | switchTitleNames_6: 384 | switchTitleNames_7: 385 | switchTitleNames_8: 386 | switchTitleNames_9: 387 | switchTitleNames_10: 388 | switchTitleNames_11: 389 | switchTitleNames_12: 390 | switchTitleNames_13: 391 | switchTitleNames_14: 392 | switchPublisherNames_0: 393 | switchPublisherNames_1: 394 | switchPublisherNames_2: 395 | switchPublisherNames_3: 396 | switchPublisherNames_4: 397 | switchPublisherNames_5: 398 | switchPublisherNames_6: 399 | switchPublisherNames_7: 400 | switchPublisherNames_8: 401 | switchPublisherNames_9: 402 | switchPublisherNames_10: 403 | switchPublisherNames_11: 404 | switchPublisherNames_12: 405 | switchPublisherNames_13: 406 | switchPublisherNames_14: 407 | switchIcons_0: {fileID: 0} 408 | switchIcons_1: {fileID: 0} 409 | switchIcons_2: {fileID: 0} 410 | switchIcons_3: {fileID: 0} 411 | switchIcons_4: {fileID: 0} 412 | switchIcons_5: {fileID: 0} 413 | switchIcons_6: {fileID: 0} 414 | switchIcons_7: {fileID: 0} 415 | switchIcons_8: {fileID: 0} 416 | switchIcons_9: {fileID: 0} 417 | switchIcons_10: {fileID: 0} 418 | switchIcons_11: {fileID: 0} 419 | switchIcons_12: {fileID: 0} 420 | switchIcons_13: {fileID: 0} 421 | switchIcons_14: {fileID: 0} 422 | switchSmallIcons_0: {fileID: 0} 423 | switchSmallIcons_1: {fileID: 0} 424 | switchSmallIcons_2: {fileID: 0} 425 | switchSmallIcons_3: {fileID: 0} 426 | switchSmallIcons_4: {fileID: 0} 427 | switchSmallIcons_5: {fileID: 0} 428 | switchSmallIcons_6: {fileID: 0} 429 | switchSmallIcons_7: {fileID: 0} 430 | switchSmallIcons_8: {fileID: 0} 431 | switchSmallIcons_9: {fileID: 0} 432 | switchSmallIcons_10: {fileID: 0} 433 | switchSmallIcons_11: {fileID: 0} 434 | switchSmallIcons_12: {fileID: 0} 435 | switchSmallIcons_13: {fileID: 0} 436 | switchSmallIcons_14: {fileID: 0} 437 | switchManualHTML: 438 | switchAccessibleURLs: 439 | switchLegalInformation: 440 | switchMainThreadStackSize: 1048576 441 | switchPresenceGroupId: 0x0005000C10000001 442 | switchLogoHandling: 0 443 | switchReleaseVersion: 0 444 | switchDisplayVersion: 1.0.0 445 | switchStartupUserAccount: 0 446 | switchTouchScreenUsage: 0 447 | switchSupportedLanguagesMask: 0 448 | switchLogoType: 0 449 | switchApplicationErrorCodeCategory: 450 | switchUserAccountSaveDataSize: 0 451 | switchUserAccountSaveDataJournalSize: 0 452 | switchApplicationAttribute: 0 453 | switchCardSpecSize: 4 454 | switchCardSpecClock: 25 455 | switchRatingsMask: 0 456 | switchRatingsInt_0: 0 457 | switchRatingsInt_1: 0 458 | switchRatingsInt_2: 0 459 | switchRatingsInt_3: 0 460 | switchRatingsInt_4: 0 461 | switchRatingsInt_5: 0 462 | switchRatingsInt_6: 0 463 | switchRatingsInt_7: 0 464 | switchRatingsInt_8: 0 465 | switchRatingsInt_9: 0 466 | switchRatingsInt_10: 0 467 | switchRatingsInt_11: 0 468 | switchLocalCommunicationIds_0: 0x0005000C10000001 469 | switchLocalCommunicationIds_1: 470 | switchLocalCommunicationIds_2: 471 | switchLocalCommunicationIds_3: 472 | switchLocalCommunicationIds_4: 473 | switchLocalCommunicationIds_5: 474 | switchLocalCommunicationIds_6: 475 | switchLocalCommunicationIds_7: 476 | switchParentalControl: 0 477 | switchAllowsScreenshot: 1 478 | switchAllowsVideoCapturing: 1 479 | switchAllowsRuntimeAddOnContentInstall: 0 480 | switchDataLossConfirmation: 0 481 | switchSupportedNpadStyles: 3 482 | switchSocketConfigEnabled: 0 483 | switchTcpInitialSendBufferSize: 32 484 | switchTcpInitialReceiveBufferSize: 64 485 | switchTcpAutoSendBufferSizeMax: 256 486 | switchTcpAutoReceiveBufferSizeMax: 256 487 | switchUdpSendBufferSize: 9 488 | switchUdpReceiveBufferSize: 42 489 | switchSocketBufferEfficiency: 4 490 | switchSocketInitializeEnabled: 1 491 | switchNetworkInterfaceManagerInitializeEnabled: 1 492 | switchPlayerConnectionEnabled: 1 493 | ps4NPAgeRating: 12 494 | ps4NPTitleSecret: 495 | ps4NPTrophyPackPath: 496 | ps4ParentalLevel: 1 497 | ps4ContentID: ED1633-NPXX51362_00-0000000000000000 498 | ps4Category: 0 499 | ps4MasterVersion: 01.00 500 | ps4AppVersion: 01.00 501 | ps4AppType: 0 502 | ps4ParamSfxPath: 503 | ps4VideoOutPixelFormat: 0 504 | ps4VideoOutInitialWidth: 1920 505 | ps4VideoOutBaseModeInitialWidth: 1920 506 | ps4VideoOutReprojectionRate: 120 507 | ps4PronunciationXMLPath: 508 | ps4PronunciationSIGPath: 509 | ps4BackgroundImagePath: 510 | ps4StartupImagePath: 511 | ps4StartupImagesFolder: 512 | ps4IconImagesFolder: 513 | ps4SaveDataImagePath: 514 | ps4SdkOverride: 515 | ps4BGMPath: 516 | ps4ShareFilePath: 517 | ps4ShareOverlayImagePath: 518 | ps4PrivacyGuardImagePath: 519 | ps4NPtitleDatPath: 520 | ps4RemotePlayKeyAssignment: -1 521 | ps4RemotePlayKeyMappingDir: 522 | ps4PlayTogetherPlayerCount: 0 523 | ps4EnterButtonAssignment: 1 524 | ps4ApplicationParam1: 0 525 | ps4ApplicationParam2: 0 526 | ps4ApplicationParam3: 0 527 | ps4ApplicationParam4: 0 528 | ps4DownloadDataSize: 0 529 | ps4GarlicHeapSize: 2048 530 | ps4ProGarlicHeapSize: 2560 531 | ps4Passcode: IOIel5N6Nd1mkpGRoR3vohRmhZKPpKdK 532 | ps4pnSessions: 1 533 | ps4pnPresence: 1 534 | ps4pnFriends: 1 535 | ps4pnGameCustomData: 1 536 | playerPrefsSupport: 0 537 | restrictedAudioUsageRights: 0 538 | ps4UseResolutionFallback: 0 539 | ps4ReprojectionSupport: 0 540 | ps4UseAudio3dBackend: 0 541 | ps4SocialScreenEnabled: 0 542 | ps4ScriptOptimizationLevel: 3 543 | ps4Audio3dVirtualSpeakerCount: 14 544 | ps4attribCpuUsage: 0 545 | ps4PatchPkgPath: 546 | ps4PatchLatestPkgPath: 547 | ps4PatchChangeinfoPath: 548 | ps4PatchDayOne: 0 549 | ps4attribUserManagement: 0 550 | ps4attribMoveSupport: 0 551 | ps4attrib3DSupport: 0 552 | ps4attribShareSupport: 0 553 | ps4attribExclusiveVR: 0 554 | ps4disableAutoHideSplash: 0 555 | ps4videoRecordingFeaturesUsed: 0 556 | ps4contentSearchFeaturesUsed: 0 557 | ps4attribEyeToEyeDistanceSettingVR: 0 558 | ps4IncludedModules: [] 559 | monoEnv: 560 | psp2Splashimage: {fileID: 0} 561 | psp2NPTrophyPackPath: 562 | psp2NPSupportGBMorGJP: 0 563 | psp2NPAgeRating: 12 564 | psp2NPTitleDatPath: 565 | psp2NPCommsID: 566 | psp2NPCommunicationsID: 567 | psp2NPCommsPassphrase: 568 | psp2NPCommsSig: 569 | psp2ParamSfxPath: 570 | psp2ManualPath: 571 | psp2LiveAreaGatePath: 572 | psp2LiveAreaBackroundPath: 573 | psp2LiveAreaPath: 574 | psp2LiveAreaTrialPath: 575 | psp2PatchChangeInfoPath: 576 | psp2PatchOriginalPackage: 577 | psp2PackagePassword: 1GMpJWxMsH35CZQ3fh5Mu615zEQfG3Uc 578 | psp2KeystoneFile: 579 | psp2MemoryExpansionMode: 0 580 | psp2DRMType: 0 581 | psp2StorageType: 0 582 | psp2MediaCapacity: 0 583 | psp2DLCConfigPath: 584 | psp2ThumbnailPath: 585 | psp2BackgroundPath: 586 | psp2SoundPath: 587 | psp2TrophyCommId: 588 | psp2TrophyPackagePath: 589 | psp2PackagedResourcesPath: 590 | psp2SaveDataQuota: 10240 591 | psp2ParentalLevel: 1 592 | psp2ShortTitle: Not Set 593 | psp2ContentID: IV0000-ABCD12345_00-0123456789ABCDEF 594 | psp2Category: 0 595 | psp2MasterVersion: 01.00 596 | psp2AppVersion: 01.00 597 | psp2TVBootMode: 0 598 | psp2EnterButtonAssignment: 2 599 | psp2TVDisableEmu: 0 600 | psp2AllowTwitterDialog: 1 601 | psp2Upgradable: 0 602 | psp2HealthWarning: 0 603 | psp2UseLibLocation: 0 604 | psp2InfoBarOnStartup: 0 605 | psp2InfoBarColor: 0 606 | psp2ScriptOptimizationLevel: 0 607 | psmSplashimage: {fileID: 0} 608 | splashScreenBackgroundSourceLandscape: {fileID: 0} 609 | splashScreenBackgroundSourcePortrait: {fileID: 0} 610 | spritePackerPolicy: 611 | webGLMemorySize: 256 612 | webGLExceptionSupport: 0 613 | webGLNameFilesAsHashes: 0 614 | webGLDataCaching: 0 615 | webGLDebugSymbols: 0 616 | webGLEmscriptenArgs: 617 | webGLModulesDirectory: 618 | webGLTemplate: APPLICATION:Default 619 | webGLAnalyzeBuildSize: 0 620 | webGLUseEmbeddedResources: 0 621 | webGLUseWasm: 0 622 | webGLCompressionFormat: 1 623 | scriptingDefineSymbols: {} 624 | platformArchitecture: 625 | iOS: 0 626 | scriptingBackend: 627 | Android: 0 628 | Standalone: 0 629 | WebGL: 1 630 | iOS: 1 631 | incrementalIl2cppBuild: {} 632 | additionalIl2CppArgs: 633 | scriptingRuntimeVersion: 1 634 | apiCompatibilityLevelPerPlatform: {} 635 | m_RenderingPath: 1 636 | m_MobileRenderingPath: 1 637 | metroPackageName: New Unity Project 638 | metroPackageVersion: 639 | metroCertificatePath: 640 | metroCertificatePassword: 641 | metroCertificateSubject: 642 | metroCertificateIssuer: 643 | metroCertificateNotAfter: 0000000000000000 644 | metroApplicationDescription: New Unity Project 645 | wsaImages: {} 646 | metroTileShortName: 647 | metroCommandLineArgsFile: 648 | metroTileShowName: 0 649 | metroMediumTileShowName: 0 650 | metroLargeTileShowName: 0 651 | metroWideTileShowName: 0 652 | metroDefaultTileSize: 1 653 | metroTileForegroundText: 1 654 | metroTileBackgroundColor: {r: 0, g: 0, b: 0, a: 1} 655 | metroSplashScreenBackgroundColor: {r: 0, g: 0, b: 0, a: 1} 656 | metroSplashScreenUseBackgroundColor: 0 657 | platformCapabilities: {} 658 | metroFTAName: 659 | metroFTAFileTypes: [] 660 | metroProtocolName: 661 | metroCompilationOverrides: 1 662 | tizenProductDescription: 663 | tizenProductURL: 664 | tizenSigningProfileName: 665 | tizenGPSPermissions: 0 666 | tizenMicrophonePermissions: 0 667 | tizenDeploymentTarget: 668 | tizenDeploymentTargetType: -1 669 | tizenMinOSVersion: 1 670 | n3dsUseExtSaveData: 0 671 | n3dsCompressStaticMem: 1 672 | n3dsExtSaveDataNumber: 0x12345 673 | n3dsStackSize: 131072 674 | n3dsTargetPlatform: 2 675 | n3dsRegion: 7 676 | n3dsMediaSize: 0 677 | n3dsLogoStyle: 3 678 | n3dsTitle: GameName 679 | n3dsProductCode: 680 | n3dsApplicationId: 0xFF3FF 681 | XboxOneProductId: 682 | XboxOneUpdateKey: 683 | XboxOneSandboxId: 684 | XboxOneContentId: 685 | XboxOneTitleId: 686 | XboxOneSCId: 687 | XboxOneGameOsOverridePath: 688 | XboxOnePackagingOverridePath: 689 | XboxOneAppManifestOverridePath: 690 | XboxOnePackageEncryption: 0 691 | XboxOnePackageUpdateGranularity: 2 692 | XboxOneDescription: 693 | XboxOneLanguage: 694 | - enus 695 | XboxOneCapability: [] 696 | XboxOneGameRating: {} 697 | XboxOneIsContentPackage: 0 698 | XboxOneEnableGPUVariability: 0 699 | XboxOneSockets: {} 700 | XboxOneSplashScreen: {fileID: 0} 701 | XboxOneAllowedProductIds: [] 702 | XboxOnePersistentLocalStorageSize: 0 703 | XboxOneXTitleMemory: 8 704 | xboxOneScriptCompiler: 0 705 | vrEditorSettings: 706 | daydream: 707 | daydreamIconForeground: {fileID: 0} 708 | daydreamIconBackground: {fileID: 0} 709 | cloudServicesEnabled: 710 | Analytics: 0 711 | Build: 0 712 | Collab: 0 713 | ErrorHub: 0 714 | Game_Performance: 0 715 | Hub: 0 716 | Purchasing: 0 717 | UNet: 0 718 | Unity_Ads: 0 719 | facebookSdkVersion: 7.9.1 720 | apiCompatibilityLevel: 3 721 | cloudProjectId: 722 | projectName: 723 | organizationId: 724 | cloudEnabled: 0 725 | enableNativePlatformBackendsForNewInputSystem: 0 726 | disableOldInputManagerSupport: 0 727 | -------------------------------------------------------------------------------- /src/androidProj/nativeeditplugin/src/main/java/com/bkmin/android/EditBox.java: -------------------------------------------------------------------------------- 1 | package com.bkmin.android; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.graphics.Color; 7 | import android.graphics.Rect; 8 | import android.graphics.Typeface; 9 | import android.text.Editable; 10 | import android.text.InputType; 11 | import android.text.TextWatcher; 12 | import android.util.Log; 13 | import android.util.SparseArray; 14 | import android.util.TypedValue; 15 | import android.view.Gravity; 16 | import android.view.KeyEvent; 17 | import android.view.MotionEvent; 18 | import android.view.View; 19 | import android.view.ViewTreeObserver; 20 | import android.view.inputmethod.EditorInfo; 21 | import android.view.inputmethod.InputMethodManager; 22 | import android.widget.EditText; 23 | import android.widget.RelativeLayout; 24 | import android.widget.TextView; 25 | 26 | import org.json.JSONException; 27 | import org.json.JSONObject; 28 | 29 | public class EditBox { 30 | // Simplest way to notify the EditBox about the application lifecycle. 31 | class EditTextLifeCycle extends EditText { 32 | EditBox observerBox; 33 | 34 | public EditTextLifeCycle(Context context, EditBox box) { 35 | super(context); 36 | this.observerBox = box; 37 | } 38 | 39 | @Override 40 | public void onWindowFocusChanged(boolean hasWindowFocus) { 41 | super.onWindowFocusChanged(hasWindowFocus); 42 | if (!hasWindowFocus) 43 | observerBox.notifyFocusChanged(hasWindowFocus); 44 | } 45 | } 46 | 47 | private EditTextLifeCycle edit; 48 | private final RelativeLayout layout; 49 | private int tag; 50 | private int characterLimit; 51 | 52 | private static SparseArray editBoxMap = null; 53 | private static InputMethodManager inputMethodManager; 54 | private static int keyboardHeight = 0; 55 | private static int keyboardHeightThreshold = 0; 56 | 57 | private static final String MSG_CREATE = "CreateEdit"; 58 | private static final String MSG_REMOVE = "RemoveEdit"; 59 | private static final String MSG_SET_TEXT = "SetText"; 60 | private static final String MSG_SET_RECT = "SetRect"; 61 | private static final String MSG_SET_TEXTSIZE = "SetTextSize"; 62 | private static final String MSG_SET_FOCUS = "SetFocus"; 63 | private static final String MSG_SET_VISIBLE = "SetVisible"; 64 | private static final String MSG_TEXT_CHANGE = "TextChange"; 65 | private static final String MSG_TEXT_BEGIN_EDIT = "TextBeginEdit"; 66 | private static final String MSG_TEXT_END_EDIT = "TextEndEdit"; 67 | private static final String MSG_ANDROID_KEY_DOWN = "AndroidKeyDown"; 68 | private static final String MSG_RETURN_PRESSED = "ReturnPressed"; 69 | 70 | static void processRecvJsonMsg(RelativeLayout mainLayout, int nSenderId, final String strJson) { 71 | if (editBoxMap == null) { 72 | editBoxMap = new SparseArray<>(); 73 | // add listener to get keyboard height 74 | keyboardHeightThreshold = NativeEditPlugin.rootView.getHeight() / 4; 75 | NativeEditPlugin.rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 76 | private Rect rect = new Rect(); 77 | private int windowVisibleBottomWithoutKeyboard = 0; 78 | 79 | @Override 80 | public void onGlobalLayout() { 81 | rect.setEmpty(); 82 | NativeEditPlugin.rootView.getWindowVisibleDisplayFrame(rect); 83 | int delta = windowVisibleBottomWithoutKeyboard - rect.bottom; 84 | if (delta > keyboardHeightThreshold) { 85 | boolean firstSetKeyboardHeight = keyboardHeight == 0; 86 | keyboardHeight = delta; 87 | if (firstSetKeyboardHeight) 88 | // keyboardHeight has not been set when trying to input for the 1st time. Call showKeyboard(true) manually. 89 | for (int i = 0; i < editBoxMap.size(); i++) { 90 | EditBox box = editBoxMap.valueAt(i); 91 | if (box.isFocused()) { 92 | box.showKeyboard(true); 93 | break; 94 | } 95 | } 96 | } else { 97 | windowVisibleBottomWithoutKeyboard = rect.bottom; 98 | } 99 | } 100 | }); 101 | } 102 | 103 | try { 104 | JSONObject jsonMsg = new JSONObject(strJson); 105 | String msg = jsonMsg.getString("msg"); 106 | 107 | if (msg.equals(MSG_CREATE)) { 108 | EditBox nb = new EditBox(mainLayout); 109 | nb.Create(nSenderId, jsonMsg); 110 | editBoxMap.append(nSenderId, nb); 111 | } else { 112 | EditBox eb = editBoxMap.get(nSenderId); 113 | if (eb != null) { 114 | eb.processJsonMsg(jsonMsg); 115 | } else { 116 | Log.e(NativeEditPlugin.LOG_TAG, "EditBox not found, id : " + nSenderId); 117 | } 118 | } 119 | } catch (JSONException e) { 120 | } 121 | } 122 | 123 | @SuppressLint("ClickableViewAccessibility") 124 | private EditBox(RelativeLayout mainLayout) { 125 | layout = mainLayout; 126 | edit = null; 127 | 128 | //Tap on the layout to clear focus of EditText 129 | layout.setOnTouchListener(new View.OnTouchListener() { 130 | @Override 131 | public boolean onTouch(View view, MotionEvent motionEvent) { 132 | layout.setFocusable(true); 133 | layout.setFocusableInTouchMode(true); 134 | layout.requestFocus(); 135 | return false; 136 | } 137 | }); 138 | } 139 | 140 | private void showKeyboard(boolean isShow) { 141 | if (inputMethodManager == null) 142 | inputMethodManager = (InputMethodManager) NativeEditPlugin.unityActivity.getSystemService(Activity.INPUT_METHOD_SERVICE); 143 | 144 | int scrollY = 0; 145 | if (isShow) { 146 | inputMethodManager.showSoftInput(edit, InputMethodManager.SHOW_FORCED); 147 | RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) edit.getLayoutParams(); 148 | int bottomMargin = layout.getHeight() - lp.topMargin - lp.height; 149 | if (bottomMargin < keyboardHeight) 150 | // Keyboard will cover the EditText. Scroll up rootView to show whole area of EditText just above keyboard. 151 | scrollY = keyboardHeight - bottomMargin; 152 | } else { 153 | NativeEditPlugin.unityActivity.getWindow().getDecorView().clearFocus(); 154 | inputMethodManager.hideSoftInputFromWindow(edit.getWindowToken(), 0); 155 | } 156 | NativeEditPlugin.rootView.setScrollY(scrollY); 157 | } 158 | 159 | private void notifyFocusChanged(boolean hasWindowFocus) { 160 | if (!hasWindowFocus) 161 | showKeyboard(false); 162 | } 163 | 164 | private void processJsonMsg(JSONObject jsonMsg) { 165 | try { 166 | String msg = jsonMsg.getString("msg"); 167 | 168 | switch (msg) { 169 | case MSG_REMOVE: 170 | this.Remove(); 171 | break; 172 | case MSG_SET_TEXT: 173 | String text = jsonMsg.getString("text"); 174 | this.SetText(text); 175 | break; 176 | case MSG_SET_RECT: 177 | this.SetRect(jsonMsg); 178 | break; 179 | case MSG_SET_TEXTSIZE: 180 | this.SetTextSize(jsonMsg); 181 | break; 182 | case MSG_SET_FOCUS: 183 | boolean isFocus = jsonMsg.getBoolean("isFocus"); 184 | this.SetFocus(isFocus); 185 | break; 186 | case MSG_SET_VISIBLE: 187 | boolean isVisible = jsonMsg.getBoolean("isVisible"); 188 | this.SetVisible(isVisible); 189 | break; 190 | case MSG_ANDROID_KEY_DOWN: 191 | String strKey = jsonMsg.getString("key"); 192 | this.OnForceAndroidKeyDown(strKey); 193 | break; 194 | } 195 | 196 | } catch (JSONException e) { 197 | } 198 | } 199 | 200 | private void SendJsonToUnity(JSONObject jsonToUnity) { 201 | try { 202 | jsonToUnity.put("senderId", this.tag); 203 | } catch (JSONException e) { 204 | } 205 | NativeEditPlugin.SendUnityMessage(jsonToUnity); 206 | } 207 | 208 | private void Create(int _tag, JSONObject jsonObj) { 209 | this.tag = _tag; 210 | 211 | try { 212 | String placeHolder = jsonObj.getString("placeHolder"); 213 | 214 | String font = jsonObj.getString("font"); 215 | characterLimit = jsonObj.getInt("characterLimit"); 216 | 217 | int textColor_r = (int) (255.0f * jsonObj.getDouble("textColor_r")); 218 | int textColor_g = (int) (255.0f * jsonObj.getDouble("textColor_g")); 219 | int textColor_b = (int) (255.0f * jsonObj.getDouble("textColor_b")); 220 | int textColor_a = (int) (255.0f * jsonObj.getDouble("textColor_a")); 221 | int backColor_r = (int) (255.0f * jsonObj.getDouble("backColor_r")); 222 | int backColor_g = (int) (255.0f * jsonObj.getDouble("backColor_g")); 223 | int backColor_b = (int) (255.0f * jsonObj.getDouble("backColor_b")); 224 | int backColor_a = (int) (255.0f * jsonObj.getDouble("backColor_a")); 225 | int placeHolderColor_r = (int) (255.0f * jsonObj.getDouble("placeHolderColor_r")); 226 | int placeHolderColor_g = (int) (255.0f * jsonObj.getDouble("placeHolderColor_g")); 227 | int placeHolderColor_b = (int) (255.0f * jsonObj.getDouble("placeHolderColor_b")); 228 | int placeHolderColor_a = (int) (255.0f * jsonObj.getDouble("placeHolderColor_a")); 229 | 230 | String contentType = jsonObj.getString("contentType"); 231 | String inputType = jsonObj.optString("inputType"); 232 | String keyboardType = jsonObj.optString("keyboardType"); 233 | String returnKeyType = jsonObj.getString("return_key_type"); 234 | 235 | String alignment = jsonObj.getString("align"); 236 | boolean multiline = jsonObj.getBoolean("multiline"); 237 | 238 | edit = new EditTextLifeCycle(NativeEditPlugin.unityActivity.getApplicationContext(), this); 239 | 240 | // It's important to set this first as it resets some things, for example character hiding if content type is password. 241 | edit.setSingleLine(!multiline); 242 | 243 | edit.setId(0); 244 | edit.setText(""); 245 | edit.setHint(placeHolder); 246 | 247 | this.SetRect(jsonObj); 248 | edit.setPadding(0, 0, 0, 0); 249 | 250 | int editInputType = 0; 251 | switch (contentType) { 252 | case "Standard": 253 | editInputType |= InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; 254 | break; // This is default behaviour 255 | case "Autocorrected": 256 | editInputType |= InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; 257 | break; 258 | case "IntegerNumber": 259 | editInputType |= InputType.TYPE_CLASS_NUMBER; 260 | break; 261 | case "DecimalNumber": 262 | editInputType |= InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL; 263 | break; 264 | case "Alphanumeric": 265 | editInputType |= InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; 266 | break; // This is default behaviour 267 | case "Name": 268 | editInputType |= InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PERSON_NAME; 269 | break; 270 | case "EmailAddress": 271 | editInputType |= InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS; 272 | break; 273 | case "Password": 274 | editInputType |= InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; 275 | break; 276 | case "Pin": 277 | editInputType |= InputType.TYPE_CLASS_PHONE; 278 | break; 279 | 280 | case "Custom": // We need more details 281 | switch (keyboardType) { 282 | case "ASCIICapable": 283 | editInputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS; 284 | break; 285 | case "NumbersAndPunctuation": 286 | editInputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED; 287 | break; 288 | case "URL": 289 | editInputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_VARIATION_URI; 290 | break; 291 | case "NumberPad": 292 | editInputType = InputType.TYPE_CLASS_NUMBER; 293 | break; 294 | case "PhonePad": 295 | editInputType = InputType.TYPE_CLASS_PHONE; 296 | break; 297 | case "NamePhonePad": 298 | editInputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PERSON_NAME; 299 | break; 300 | case "EmailAddress": 301 | editInputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS; 302 | break; 303 | default: 304 | editInputType = InputType.TYPE_CLASS_TEXT; 305 | } 306 | switch (inputType) { 307 | case "AutoCorrect": 308 | editInputType |= InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; 309 | break; 310 | case "Password": 311 | editInputType |= InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_TEXT_VARIATION_PASSWORD; 312 | break; 313 | } 314 | break; 315 | 316 | default: 317 | editInputType |= InputType.TYPE_CLASS_TEXT; 318 | break; // No action 319 | 320 | } 321 | if (multiline) 322 | editInputType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE; 323 | edit.setInputType(editInputType); 324 | 325 | int gravity = 0; 326 | switch (alignment) { 327 | case "UpperLeft": 328 | gravity = Gravity.TOP | Gravity.START; 329 | break; 330 | case "UpperCenter": 331 | gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; 332 | break; 333 | case "UpperRight": 334 | gravity = Gravity.TOP | Gravity.END; 335 | break; 336 | case "MiddleLeft": 337 | gravity = Gravity.CENTER_VERTICAL | Gravity.START; 338 | break; 339 | case "MiddleCenter": 340 | gravity = Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL; 341 | break; 342 | case "MiddleRight": 343 | gravity = Gravity.CENTER_VERTICAL | Gravity.END; 344 | break; 345 | case "LowerLeft": 346 | gravity = Gravity.BOTTOM | Gravity.START; 347 | break; 348 | case "LowerCenter": 349 | gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; 350 | break; 351 | case "LowerRight": 352 | gravity = Gravity.BOTTOM | Gravity.END; 353 | break; 354 | } 355 | edit.setGravity(gravity); 356 | 357 | int imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI; 358 | if (!multiline) 359 | switch (returnKeyType) { 360 | case "Next": 361 | imeOptions |= EditorInfo.IME_ACTION_NEXT; 362 | break; 363 | case "Done": 364 | imeOptions |= EditorInfo.IME_ACTION_DONE; 365 | break; 366 | case "Send": 367 | imeOptions |= EditorInfo.IME_ACTION_SEND; 368 | break; 369 | case "Go": 370 | imeOptions |= EditorInfo.IME_ACTION_GO; 371 | break; 372 | } 373 | edit.setImeOptions(imeOptions); 374 | 375 | this.SetTextSize(jsonObj); 376 | edit.setTextColor(Color.argb(textColor_a, textColor_r, textColor_g, textColor_b)); 377 | edit.setBackgroundColor(Color.argb(backColor_a, backColor_r, backColor_g, backColor_b)); 378 | edit.setHintTextColor(Color.argb(placeHolderColor_a, placeHolderColor_r, placeHolderColor_g, placeHolderColor_b)); 379 | 380 | if (font != null && !font.isEmpty()) { 381 | Typeface tf = Typeface.create(font, Typeface.NORMAL); 382 | edit.setTypeface(tf); 383 | } 384 | 385 | final EditBox eb = this; 386 | 387 | edit.setOnFocusChangeListener(new View.OnFocusChangeListener() { 388 | @Override 389 | public void onFocusChange(View v, boolean hasFocus) { 390 | 391 | JSONObject msgTextEndJSON = new JSONObject(); 392 | try { 393 | msgTextEndJSON.put("msg", hasFocus ? MSG_TEXT_BEGIN_EDIT : MSG_TEXT_END_EDIT); 394 | msgTextEndJSON.put("text", eb.GetText()); 395 | } catch (JSONException e) { 396 | } 397 | eb.SendJsonToUnity(msgTextEndJSON); 398 | SetFocus(hasFocus); 399 | } 400 | }); 401 | 402 | edit.addTextChangedListener(new TextWatcher() { 403 | 404 | public void afterTextChanged(Editable s) { 405 | if (characterLimit > 0 && s.length() >= characterLimit + 1) { 406 | s.delete(s.length() - 1, s.length()); 407 | edit.removeTextChangedListener(this); 408 | edit.setText(s); 409 | edit.setSelection(s.length()); 410 | edit.addTextChangedListener(this); 411 | } 412 | 413 | JSONObject jsonToUnity = new JSONObject(); 414 | try { 415 | jsonToUnity.put("msg", MSG_TEXT_CHANGE); 416 | jsonToUnity.put("text", s.toString()); 417 | } catch (JSONException e) { 418 | } 419 | eb.SendJsonToUnity(jsonToUnity); 420 | } 421 | 422 | @Override 423 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 424 | 425 | } 426 | 427 | @Override 428 | public void onTextChanged(CharSequence s, int start, int before, int count) { 429 | 430 | } 431 | }); 432 | 433 | edit.setOnEditorActionListener(new TextView.OnEditorActionListener() { 434 | @Override 435 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 436 | if (actionId == EditorInfo.IME_ACTION_NEXT 437 | || actionId == EditorInfo.IME_ACTION_DONE 438 | || actionId == EditorInfo.IME_ACTION_SEND 439 | || actionId == EditorInfo.IME_ACTION_GO) { 440 | JSONObject jsonToUnity = new JSONObject(); 441 | try { 442 | jsonToUnity.put("msg", MSG_RETURN_PRESSED); 443 | } catch (JSONException e) { 444 | } 445 | 446 | eb.SendJsonToUnity(jsonToUnity); 447 | return true; 448 | } 449 | return false; 450 | } 451 | }); 452 | 453 | layout.addView(edit); 454 | 455 | } catch (JSONException e) { 456 | Log.i(NativeEditPlugin.LOG_TAG, String.format("Create editbox error %s", e.getMessage())); 457 | } 458 | } 459 | 460 | private void Remove() { 461 | if (edit != null) { 462 | layout.removeView(edit); 463 | editBoxMap.remove(this.tag); 464 | } 465 | edit = null; 466 | } 467 | 468 | private void SetText(String newText) { 469 | if (edit != null) { 470 | int cursorPos = edit.getSelectionStart(); 471 | int previousLength = edit.getText().length(); 472 | 473 | edit.setText(newText); 474 | 475 | // Update text selection (cursor position) to be the same after editing text 476 | // If the user had multiple characters selected, we are losing them and get the cursor in only one position 477 | if (previousLength == cursorPos) { 478 | //The cursor was at the end of the text, let us put it again at the end of the text in case more characters were added 479 | cursorPos = newText.length(); 480 | } 481 | 482 | if (cursorPos > newText.length()) { 483 | //Text was deleted, so cursor position is after the end of the text, let's put it at the last position 484 | cursorPos = newText.length(); 485 | } 486 | edit.setSelection(cursorPos); 487 | } 488 | } 489 | 490 | private String GetText() { 491 | return edit.getText().toString(); 492 | } 493 | 494 | private boolean isFocused() { 495 | return edit.isFocused(); 496 | } 497 | 498 | private void SetFocus(boolean isFocus) { 499 | if (isFocus) { 500 | edit.requestFocus(); 501 | } else { 502 | edit.clearFocus(); 503 | } 504 | this.showKeyboard(isFocus); 505 | } 506 | 507 | private void SetTextSize(JSONObject jsonRect) { 508 | try { 509 | double fontSize = jsonRect.getDouble("fontSize"); 510 | edit.setTextSize(TypedValue.COMPLEX_UNIT_PX, (float) fontSize); 511 | } catch (JSONException e) { 512 | } 513 | } 514 | 515 | private void SetRect(JSONObject jsonRect) { 516 | try { 517 | double x = jsonRect.getDouble("x") * layout.getWidth(); 518 | double y = jsonRect.getDouble("y") * layout.getHeight(); 519 | double width = jsonRect.getDouble("width") * layout.getWidth(); 520 | double height = jsonRect.getDouble("height") * layout.getHeight(); 521 | 522 | RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int) width, (int) height); 523 | lp.setMargins((int) x, (int) y, 0, 0); 524 | edit.setLayoutParams(lp); 525 | } catch (JSONException e) { 526 | } 527 | } 528 | 529 | private void SetVisible(boolean bVisible) { 530 | edit.setEnabled(bVisible); 531 | edit.setVisibility(bVisible ? View.VISIBLE : View.INVISIBLE); 532 | } 533 | 534 | private void OnForceAndroidKeyDown(String strKey) { 535 | if (!this.isFocused()) return; 536 | 537 | // Need to force fire key event of backspace and enter because Unity eats them and never return back to plugin. 538 | // Same happens on number keys on top of the keyboard with Google Keyboard on password fields. 539 | int keyCode = -1; 540 | if (strKey.equalsIgnoreCase("backspace")) { 541 | keyCode = KeyEvent.KEYCODE_DEL; 542 | } else if (strKey.equalsIgnoreCase("enter")) { 543 | keyCode = KeyEvent.KEYCODE_ENTER; 544 | } else if (strKey.equals("0")) { 545 | keyCode = KeyEvent.KEYCODE_0; 546 | } else if (strKey.equals("1")) { 547 | keyCode = KeyEvent.KEYCODE_1; 548 | } else if (strKey.equals("2")) { 549 | keyCode = KeyEvent.KEYCODE_2; 550 | } else if (strKey.equals("3")) { 551 | keyCode = KeyEvent.KEYCODE_3; 552 | } else if (strKey.equals("4")) { 553 | keyCode = KeyEvent.KEYCODE_4; 554 | } else if (strKey.equals("5")) { 555 | keyCode = KeyEvent.KEYCODE_5; 556 | } else if (strKey.equals("6")) { 557 | keyCode = KeyEvent.KEYCODE_6; 558 | } else if (strKey.equals("7")) { 559 | keyCode = KeyEvent.KEYCODE_7; 560 | } else if (strKey.equals("8")) { 561 | keyCode = KeyEvent.KEYCODE_8; 562 | } else if (strKey.equals("9")) { 563 | keyCode = KeyEvent.KEYCODE_9; 564 | } 565 | if (keyCode > 0) { 566 | KeyEvent ke = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); 567 | Log.i(NativeEditPlugin.LOG_TAG, String.format("Force fire KEY EVENT %d", keyCode)); 568 | edit.onKeyDown(keyCode, ke); 569 | } 570 | } 571 | } 572 | --------------------------------------------------------------------------------