├── LICENSE ├── MobileNativeCode ├── MobileNativeCode.uplugin ├── Resources │ └── Icon128.png └── Source │ └── MobileNativeCode │ ├── MobileNativeCode.Build.cs │ ├── MobileNativeCode_UPL_Android.xml │ ├── MobileNativeCode_UPL_iOS.xml │ ├── Private │ ├── Android │ │ ├── Java │ │ │ ├── DeviceInfo.java │ │ │ ├── ExampleArrayClass.java │ │ │ ├── HelloWorldClass.java │ │ │ ├── MyJavaObjects.java │ │ │ ├── NativeUI.java │ │ │ ├── asyncHelloWorldClass.java │ │ │ ├── drawable │ │ │ │ └── my_test_icon.png │ │ │ └── values │ │ │ │ └── string.xml │ │ └── Utils │ │ │ ├── AndroidUtils.cpp │ │ │ ├── AndroidUtils.h │ │ │ ├── JavaConvert.cpp │ │ │ └── JavaConvert.h │ ├── IOS │ │ ├── ObjC │ │ │ ├── IosAsyncHelloWorld.h │ │ │ ├── IosAsyncHelloWorld.mm │ │ │ ├── IosDeviceInfo.h │ │ │ ├── IosDeviceInfo.mm │ │ │ ├── IosExampleArray.h │ │ │ ├── IosExampleArray.mm │ │ │ ├── IosHelloWorld.h │ │ │ ├── IosHelloWorld.mm │ │ │ ├── IosNativeUI.h │ │ │ └── IosNativeUI.mm │ │ └── Utils │ │ │ ├── ObjC_Convert.cpp │ │ │ └── ObjC_Convert.h │ ├── MobileNativeCode.cpp │ ├── MobileNativeCodeBlueprint.cpp │ └── MobileNativeCodeEditorSettings.cpp │ ├── Public │ ├── MobileNativeCode.h │ ├── MobileNativeCodeBlueprint.h │ ├── MobileNativeCodeEditorSettings.h │ └── NativeUI │ │ └── Enums │ │ └── ToastLengthMessage.h │ └── ThirdParty │ ├── Android │ ├── arm64-v8a │ │ └── lib │ │ │ └── libc++_shared.so │ └── armeabi-v7a │ │ └── lib │ │ └── libc++_shared.so │ ├── IOS │ ├── bundle │ │ └── IosDrawable.bundle │ │ │ └── my_test_icon.png │ └── frameworks │ │ ├── GoogleMobileAdsMediationTestSuite.embeddedframework.zip │ │ └── PersonalizedAdConsent.embeddedframework.zip │ └── Windows │ ├── include │ └── .h or .cpp file .txt │ └── lib │ └── .dll or . lib file .txt ├── README.md └── screenshot ├── CallJava4.png ├── EnablePlugin1.png ├── HonorPlay_2.png ├── IOS_framework2.png ├── JavaBundle_Android.png ├── Javap_Android.png ├── LevelBlueprint2.png ├── Logo3.png ├── PathPlugin2.png └── iPhone7_2.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sovahero 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MobileNativeCode/MobileNativeCode.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "2.5", 5 | "FriendlyName": "MobileNativeCode", 6 | "Description": "Code utils for mobile platforms", 7 | "Category": "Mobile", 8 | "CreatedBy": "Sovahero", 9 | "CreatedByURL": "", 10 | "DocsURL": "https://github.com/Sovahero/PluginMobileNativeCode", 11 | "MarketplaceURL": "", 12 | "SupportURL": "https://github.com/Sovahero/PluginMobileNativeCode/issues", 13 | "CanContainContent": false, 14 | "IsBetaVersion": false, 15 | "IsExperimentalVersion": false, 16 | "Installed": true, 17 | "EnabledByDefault": false, 18 | "RequiresBuildPlatform": true, 19 | "Modules": [ 20 | { 21 | "Name": "MobileNativeCode", 22 | "Type": "Runtime", 23 | "LoadingPhase": "Default", 24 | "WhitelistPlatforms": [ 25 | "Win64", 26 | "Mac", 27 | "Android", 28 | "IOS" 29 | ] 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /MobileNativeCode/Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/MobileNativeCode/Resources/Icon128.png -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/MobileNativeCode.Build.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using UnrealBuildTool; 3 | using System.Collections.Generic; 4 | 5 | public class MobileNativeCode : ModuleRules 6 | { 7 | //=======Path=================================================================== 8 | private string ThirdPartyPath 9 | { 10 | get { return Path.GetFullPath(Path.Combine(ModuleDirectory, "ThirdParty/")); } 11 | } 12 | 13 | private string PathThirdPartyAndroid 14 | { 15 | get { return Path.GetFullPath(Path.Combine(ThirdPartyPath, "Android/")); } 16 | } 17 | 18 | private string PathThirdPartyIOS 19 | { 20 | get { return Path.GetFullPath(Path.Combine(ThirdPartyPath, "IOS/")); } 21 | } 22 | 23 | private string PathThirdPartyWindows 24 | { 25 | get { return Path.GetFullPath(Path.Combine(ThirdPartyPath, "Windows/")); } 26 | } 27 | 28 | private void AddFrameworks(string[] frameworks) 29 | { 30 | for (int i = 0; i < frameworks.Length; i += 2) 31 | { 32 | if ((i % 2) == 0) 33 | { 34 | if (frameworks[i + 1] == "") 35 | { 36 | PublicAdditionalFrameworks.Add( 37 | new Framework( 38 | frameworks[i], 39 | Path.Combine(PathThirdPartyIOS, "frameworks", frameworks[i] + ".embeddedframework.zip") 40 | ) 41 | ); 42 | } 43 | else 44 | { 45 | PublicAdditionalFrameworks.Add( 46 | new Framework( 47 | frameworks[i], 48 | Path.Combine(PathThirdPartyIOS, "frameworks", frameworks[i] + ".embeddedframework.zip"), 49 | Path.Combine(frameworks[i] + ".framework/" + frameworks[i+1] + ".bundle") 50 | ) 51 | ); 52 | } 53 | } 54 | } 55 | } 56 | 57 | private void AddBundles(string[] bundles) 58 | { 59 | foreach (string thisBundle in bundles) 60 | { 61 | BundleResource newBundle = new BundleResource(Path.Combine(PathThirdPartyIOS, "bundle", thisBundle + ".bundle")); 62 | AdditionalBundleResources.Add(newBundle); 63 | } 64 | } 65 | 66 | //=======Main================================================================== 67 | public MobileNativeCode(ReadOnlyTargetRules Target) : base(Target) 68 | { 69 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 70 | 71 | PublicIncludePaths.AddRange(new string[] { Path.Combine(ModuleDirectory, "Public") }); 72 | PrivateIncludePaths.AddRange(new string[] { Path.Combine(ModuleDirectory, "Private") }); 73 | 74 | PublicDependencyModuleNames.AddRange(new string[] 75 | { 76 | "Engine", 77 | "Core", 78 | "CoreUObject", 79 | "InputCore", 80 | } 81 | ); 82 | 83 | PrivateDependencyModuleNames.AddRange(new string[] 84 | { 85 | "Slate", 86 | "SlateCore" 87 | } 88 | ); 89 | 90 | //-- Additional build steps 91 | LoadLib(Target); 92 | } 93 | 94 | //=====Enable libraries depending on the platform================ 95 | public void LoadLib(ReadOnlyTargetRules Target) 96 | { 97 | //== If the Windows platform 98 | if (Target.Platform == UnrealTargetPlatform.Win64) 99 | { 100 | //Add Include path 101 | PublicIncludePaths.Add(Path.Combine(PathThirdPartyWindows, "include")); 102 | 103 | string[] Libs = { 104 | /*"example.lib", 105 | "example2.lib"*/ 106 | }; 107 | 108 | string[] DLLs = { 109 | /*"example.dll", 110 | "example2.dll"*/ 111 | }; 112 | 113 | //Add Static Libraries Win 114 | foreach (string Lib in Libs) 115 | { 116 | PublicAdditionalLibraries.Add(Path.Combine(PathThirdPartyWindows, "lib", Lib)); 117 | } 118 | 119 | //Add Dynamic Libraries Win 120 | foreach (string DLL in DLLs) 121 | { 122 | PublicDelayLoadDLLs.Add(Path.Combine(PathThirdPartyWindows, "lib", DLL)); 123 | } 124 | } 125 | 126 | //== If the Android platform 127 | else if (Target.Platform == UnrealTargetPlatform.Android) 128 | { 129 | string ArchArmV7a = "armeabi-v7a"; 130 | string ArchArmV8a = "arm64-v8a"; 131 | 132 | //for JNI 133 | PrivateDependencyModuleNames.AddRange(new string[] 134 | { 135 | "Launch" 136 | } 137 | ); 138 | 139 | //------ .h-------------------- 140 | PrivateIncludePaths.AddRange(new string[] { Path.Combine(ModuleDirectory, "Private", "Android") }); 141 | //----- .so ------------------ 142 | // To connect .so dynamic libraries also need to be added to .xml file 143 | 144 | // libc++_shared.so already added, but if you use the engine version 4.24 or less, you can uncomment these lines and in xml 145 | string[] Libs = { 146 | //"libc++_shared.so", 147 | }; 148 | 149 | foreach (string Lib in Libs) 150 | { 151 | PublicAdditionalLibraries.Add(Path.Combine(PathThirdPartyAndroid, ArchArmV7a, "lib", Lib)); 152 | PublicAdditionalLibraries.Add(Path.Combine(PathThirdPartyAndroid, ArchArmV8a, "lib", Lib)); 153 | } 154 | 155 | //-------XML--------------------------------------- 156 | /** Additional steps for building on Android. Basically, all the basic information is specified in xml. 157 | * The xml file is located on the path: "Plugins\MobileNativeCode\Source\MobileNativeCode\MobileNativeCode_UPL_Android.xml" 158 | */ 159 | 160 | AdditionalPropertiesForReceipt.Add("AndroidPlugin", Path.Combine(ModuleDirectory, "MobileNativeCode_UPL_Android.xml")); 161 | } 162 | 163 | //== If the IOS platform 164 | else if (Target.Platform == UnrealTargetPlatform.IOS) 165 | { 166 | //------------------- .define-------------------- 167 | // Redefine for the xcode compiler 168 | PublicDefinitions.Add("TARGET_TV_OS=0"); 169 | PublicDefinitions.Add("BUCK=1"); 170 | // enable ios 14 support 171 | PublicDefinitions.Add("WITH_IOS14_SUPPORT=1"); 172 | 173 | PrivateDependencyModuleNames.AddRange(new string[] 174 | { 175 | "Launch" 176 | } 177 | ); 178 | 179 | //----------------- p-list ------------------ 180 | /** The xml file specifies additional lines for Info.plist 181 | * The xml file is located on the path: "Plugins\MobileNativeCode\Source\MobileNativeCode\MobileNativeCode_UPL_iOS.xml" 182 | */ 183 | 184 | AdditionalPropertiesForReceipt.Add("IOSPlugin", Path.Combine(ModuleDirectory, "MobileNativeCode_UPL_iOS.xml")); 185 | 186 | //------------------- .h -------------------- 187 | PrivateIncludePaths.AddRange(new string[] { Path.Combine(ModuleDirectory, "Private", "IOS") }); 188 | 189 | //------------------- Public framework------------------------------------ 190 | /** A list of public frameworks from Apple that you need to use when building. 191 | * You can view the entire list here: https://developer.apple.com/documentation/technologies 192 | */ 193 | 194 | PublicFrameworks.AddRange( 195 | new string[] 196 | { 197 | "EventKit", 198 | "GLKit", 199 | "CoreTelephony", 200 | "SystemConfiguration", 201 | "UIKit", 202 | "Foundation", 203 | "CoreGraphics", 204 | "MobileCoreServices", 205 | "StoreKit", 206 | "CFNetwork", 207 | "CoreData", 208 | "Security", 209 | "CoreLocation", 210 | "WatchConnectivity", 211 | "MediaPlayer", 212 | "CoreFoundation", 213 | "AdSupport", 214 | "MessageUI", 215 | "AppTrackingTransparency", 216 | "WebKit", 217 | "AVFoundation", 218 | "Accelerate", 219 | "LocalAuthentication", 220 | "SafariServices", 221 | "AuthenticationServices", 222 | "UserNotifications", 223 | } 224 | ); 225 | 226 | //------------------- Private framework--------------------------------------- 227 | /** Third-party libraries are called frameworks and are connected in this line. 228 | * 229 | * To get the framework and use it in the UE4 build system. It should have the following folder structure: 230 | * MyNameFramework.embeddedframework.zip <== Pack in *.zip can be used in WinRar 231 | * -MyNameFramework.embeddedframework 232 | * - MyNameFramework.framework <== The source framework that is built using xcode 233 | * 234 | * List the names of your frameworks here, separated by commas. 235 | * If the framework contains its own package, 236 | * then the next line with the location in the framework of this package is added to the array after the name of the framework. 237 | * If the framework does not contain a package, an empty string is added after the name. 238 | * 239 | * For example on the path: "Plugins\MobileNativeCode\Source\MobileNativeCode\ThirdParty\IOS\frameworks" 240 | * PersonalizedAdConsent.the framework contains the PersonalizedAdConsent.bundle 241 | * in the root of the framework, so you need to specify "PersonalizedAdConsent" twice in the array. 242 | * 243 | * If *.framework does not contain a*. bundle, then the second line in the array would be empty. 244 | */ 245 | 246 | string[] frameworks = { 247 | // "PersonalizedAdConsent", "PersonalizedAdConsent", 248 | // "GoogleMobileAdsMediationTestSuite", "Resources/GoogleMobileAdsMediationTestSuite", // <== The second line indicates the location of the *.bundle in the *.framework 249 | // "ExamleMyFramework", "", // <== without *.bundle 250 | }; 251 | 252 | AddFrameworks(frameworks); 253 | 254 | //------------------- Private Bundle --------------------------------------- 255 | /** Bundle is used to package your own resources in *.ipa file 256 | * 257 | * Along the path is a test image: "Plugins\MobileNativeCode\Source\MobileNativeCode\ThirdParty\IOS\bundle\IosDrawable.bundle" 258 | * that can be used as follows in ObjC: 259 | * 260 | * NSString* bundlePath = [[NSBundle mainBundle] pathForResource: @"IosDrawable" ofType: @"bundle"]; 261 | * NSBundle* bundle = [NSBundle bundleWithPath: bundlePath]; 262 | * NSString* resource = [bundle pathForResource: @"my_test_icon" ofType: @"png"]; 263 | * NSURL* imageUrl = [NSURL fileURLWithPath: resource]; 264 | */ 265 | 266 | string[] bundles = { 267 | "IosDrawable", 268 | // "ExampleMyBundle", 269 | }; 270 | 271 | AddBundles(bundles); 272 | } 273 | } 274 | //============================================================================= 275 | } 276 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/MobileNativeCode_UPL_Android.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 52 | 53 | 54 | 55 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | android.useAndroidX=true 65 | android.enableJetifier=true 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -dontwarn com.Plugins.** 74 | -keep class com.Plugins.** { *; } 75 | -keep interface com.Plugins.** { *; } 76 | -keep public class com.Plugins.MobileNativeCode.** { public protected *; } 77 | 78 | -dontwarn androidx.** 79 | -keep class androidx.** { *; } 80 | -keep interface androidx.** { *; } 81 | 82 | -keep class com.facebook.** { *; } 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | ext { 135 | android { 136 | compileSdkVersion 34 137 | buildTypes { 138 | release { 139 | minifyEnabled false 140 | } 141 | } 142 | } 143 | } 144 | 145 | repositories { 146 | mavenCentral() 147 | jcenter() 148 | } 149 | 150 | 151 | 152 | 153 | dependencies { 154 | implementation("com.squareup.okhttp3:okhttp:3.12.13") 155 | implementation("com.squareup.okhttp3:okhttp-urlconnection:3.12.13") 156 | implementation('com.google.android.play:review:2.0.1') 157 | 158 | implementation 'com.google.guava:guava:28.2-android' 159 | implementation 'androidx.annotation:annotation:1.0.0' 160 | 161 | implementation 'androidx.work:work-runtime:2.7.1' 162 | } 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | allprojects { 172 | def mappings = [ 173 | 'android.support.annotation': 'androidx.annotation', 174 | 'android.arch.lifecycle': 'androidx.lifecycle', 175 | 'android.support.v4.app.NotificationCompat': 'androidx.core.app.NotificationCompat', 176 | 'android.support.v4.app.ActivityCompat': 'androidx.core.app.ActivityCompat', 177 | 'android.support.v4.content.ContextCompat': 'androidx.core.content.ContextCompat', 178 | 'android.support.v4.app.NotificationManagerCompat': 'androidx.core.app.NotificationManagerCompat', 179 | 'android.support.v4.content.FileProvider': 'androidx.core.content.FileProvider', 180 | 'android.support.v13.app.FragmentCompat': 'androidx.legacy.app.FragmentCompat', 181 | 'android.arch.lifecycle.Lifecycle': 'androidx.lifecycle.Lifecycle', 182 | 'android.arch.lifecycle.LifecycleObserver': 'androidx.lifecycle.LifecycleObserver', 183 | 'android.arch.lifecycle.OnLifecycleEvent': 'androidx.lifecycle.OnLifecycleEvent', 184 | 'android.arch.lifecycle.ProcessLifecycleOwner': 'androidx.lifecycle.ProcessLifecycleOwner', 185 | ] 186 | 187 | beforeEvaluate { project -> 188 | project.rootProject.projectDir.traverse(type: groovy.io.FileType.FILES, nameFilter: ~/.*\.java$/) { f -> 189 | mappings.each { entry -> 190 | if (f.getText('UTF-8').contains(entry.key)) { 191 | println "Updating ${entry.key} to ${entry.value} in file ${f}" 192 | ant.replace(file: f, token: entry.key, value: entry.value) 193 | } 194 | } 195 | } 196 | } 197 | 198 | } 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/MobileNativeCode_UPL_iOS.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Java/DeviceInfo.java: -------------------------------------------------------------------------------- 1 | package com.Plugins.MobileNativeCode; 2 | 3 | 4 | import android.app.Activity; 5 | import android.os.Build; 6 | import androidx.annotation.Keep; 7 | import android.content.Context; 8 | import java.io.File; 9 | 10 | 11 | //-- Device information 12 | @Keep 13 | public class DeviceInfo { 14 | 15 | //-- Init -- 16 | @Keep 17 | public static int Initialization(){ 18 | return 1; 19 | } 20 | 21 | //---- VersioN SDK Phone ---------------- 22 | @Keep 23 | public static int getSdkInt() { 24 | int SdkAndroid = Build.VERSION.SDK_INT; 25 | return SdkAndroid; 26 | } 27 | 28 | @Keep 29 | public static String getBrand() { 30 | return Build.BRAND; 31 | } 32 | 33 | @Keep 34 | public static String getModel() { 35 | return Build.MODEL; 36 | } 37 | 38 | //----- Path to "storage/emulated/0/Android/data/data/%APP_PACKAGE_NAME%/"------------------ 39 | @Keep 40 | public static String GetExternalFilesDir(final Activity activity) { 41 | Context context = activity; 42 | File file = context.getExternalFilesDir(null); 43 | String PathStr = file.getPath(); 44 | PathStr += "/"; 45 | 46 | return PathStr; 47 | } 48 | } -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Java/ExampleArrayClass.java: -------------------------------------------------------------------------------- 1 | package com.Plugins.MobileNativeCode;//Use only this package, do not change it!!! 2 | 3 | import androidx.annotation.Keep; 4 | 5 | 6 | @Keep 7 | public class ExampleArrayClass { 8 | 9 | //Return String Array 10 | @Keep 11 | public static String[] TestArray(String[] text, boolean[] b, int[] i, long[] l, float[] f) { 12 | 13 | /* 14 | Some clever manipulations with arrays 15 | */ 16 | 17 | String[] ArrStr = { "string", "Array" }; 18 | return ArrStr; 19 | } 20 | 21 | 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Java/HelloWorldClass.java: -------------------------------------------------------------------------------- 1 | package com.Plugins.MobileNativeCode;//Use only this package, do not change it!!! 2 | 3 | import androidx.annotation.Keep; 4 | 5 | 6 | @Keep 7 | public class HelloWorldClass { 8 | 9 | //----- Calling Java code synchronously ------------------- 10 | @Keep 11 | public static String HelloWorldOnAndroid(String text) { 12 | text += " on Android"; 13 | return text; 14 | } 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Java/MyJavaObjects.java: -------------------------------------------------------------------------------- 1 | package com.Plugins.MobileNativeCode;//Use only this package, do not change it!!! 2 | 3 | import androidx.annotation.Keep; 4 | import android.os.Bundle; 5 | 6 | @Keep 7 | public class MyJavaObjects { 8 | 9 | //----- Returns a new object of the type - Bundle ------------------- 10 | @Keep 11 | public static Bundle getBundleJava(){ 12 | return new Bundle(); 13 | } 14 | 15 | } 16 | 17 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Java/NativeUI.java: -------------------------------------------------------------------------------- 1 | package com.Plugins.MobileNativeCode; 2 | 3 | import android.app.Activity; 4 | import androidx.annotation.Keep; 5 | import android.widget.Toast; 6 | 7 | 8 | @Keep 9 | public class NativeUI { 10 | 11 | //---- Calling a pop-up message ---------------- 12 | @Keep 13 | public static void showToast(final Activity activity, final String text, final int duration) { 14 | activity.runOnUiThread(new Runnable() { 15 | @Override 16 | public void run() 17 | { 18 | Toast.makeText(activity, text, duration).show(); 19 | } 20 | }); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Java/asyncHelloWorldClass.java: -------------------------------------------------------------------------------- 1 | package com.Plugins.MobileNativeCode;//Use only this package, do not change it!!! 2 | 3 | import android.app.Activity; 4 | import androidx.annotation.Keep; 5 | 6 | 7 | @Keep 8 | public class asyncHelloWorldClass { 9 | 10 | //Calling *.cpp code 11 | @Keep 12 | public static native void CallBackCppAndroid(String returnStr); 13 | 14 | // Calling Java code asynchronously and returning the value back to C++ 15 | @Keep 16 | public static void asyncHelloWorldOnAndroid(final Activity activity, final String text) { 17 | activity.runOnUiThread(new Runnable() { 18 | @Override 19 | public void run() 20 | { 21 | CallBackCppAndroid(text+" on Android"); 22 | } 23 | }); 24 | } 25 | 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Java/drawable/my_test_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/MobileNativeCode/Source/MobileNativeCode/Private/Android/Java/drawable/my_test_icon.png -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Java/values/string.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 123456789 4 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Utils/AndroidUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "AndroidUtils.h" 2 | 3 | /** 4 | * Template functions must be in .h 5 | */ 6 | 7 | bool AndroidUtils::m_supportedPlatform = false; 8 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Utils/AndroidUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "JavaConvert.h" 8 | #include "MobileNativeCodeBlueprint.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | using namespace std; 16 | class AndroidUtils 17 | 18 | 19 | 20 | { 21 | private: 22 | static bool m_supportedPlatform; 23 | 24 | public: 25 | static void Initialization() 26 | { 27 | m_supportedPlatform = true; 28 | m_supportedPlatform = (bool)CallJavaCode( 29 | "com/Plugins/MobileNativeCode/MobileNativeCode", 30 | "Initialization", 31 | "", 32 | false 33 | ); 34 | 35 | if(!m_supportedPlatform) 36 | { 37 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> The mobile platform is not supported, all further Java functions will not be called!")); 38 | } 39 | else 40 | { 41 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Init on phone: %s"), *UMobileNativeCodeBlueprint::GetModelDevice()); 42 | } 43 | } 44 | 45 | //Can the mobile platform call functions 46 | static int isSupportPlatform() 47 | { 48 | if(!m_supportedPlatform) 49 | { 50 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> The mobile platform is not supported, all further Java functions will not be called!")); 51 | } 52 | return m_supportedPlatform; 53 | } 54 | 55 | //-- Free memory 56 | static bool DeleteJavaObject(jobject JavaObject) 57 | { 58 | if(JavaObject) 59 | { 60 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 61 | Env->DeleteLocalRef(JavaObject); 62 | JavaObject = nullptr; 63 | return true; 64 | } 65 | return false; 66 | } 67 | 68 | // -- Why do we need this structure? 69 | // -- https://stackoverflow.com/questions/47373354/c-void-argument-with-variadic-template 70 | template 71 | struct type { }; 72 | 73 | template 74 | static const anyType& convertArg(const anyType& value) 75 | { 76 | return value; 77 | } 78 | static jstring convertArg(const char* str) 79 | { 80 | return JavaConvert::GetJavaString(str); 81 | } 82 | static jstring convertArg(const std::string& str) 83 | { 84 | return JavaConvert::GetJavaString(str); 85 | } 86 | static jstring convertArg(const FString& str) 87 | { 88 | return JavaConvert::GetJavaString(str); 89 | } 90 | static jlong convertArg(long l) 91 | { 92 | return JavaConvert::GetJavaLong(l); 93 | } 94 | //---array 95 | static jobjectArray convertArg(const TArray& stringArray) 96 | { 97 | TArray tmpFString; 98 | for (auto tmpCellStringArray : stringArray) { 99 | std::string tmpString = tmpCellStringArray; 100 | tmpFString.Add(tmpString.c_str()); 101 | } 102 | return JavaConvert::ConvertToJStringArray(tmpFString); 103 | } 104 | static jobjectArray convertArg(const TArray& stringArray) 105 | { 106 | TArray tmpFString; 107 | for (auto tmpCellStringArray : stringArray) 108 | tmpFString.Add(tmpCellStringArray.c_str()); 109 | 110 | return JavaConvert::ConvertToJStringArray(tmpFString); 111 | } 112 | static jobjectArray convertArg(const TArray& stringArray) 113 | { 114 | return JavaConvert::ConvertToJStringArray(stringArray); 115 | } 116 | static jbooleanArray convertArg(const TArray& boolArray) 117 | { 118 | return JavaConvert::ConvertToJBooleanArray(boolArray); 119 | } 120 | static jintArray convertArg(const TArray& intArray) 121 | { 122 | return JavaConvert::ConvertToJIntArray(intArray); 123 | } 124 | static jbyteArray convertArg(const TArray& byteArray) 125 | { 126 | return JavaConvert::ConvertToJByteArray(byteArray); 127 | } 128 | static jlongArray convertArg(const TArray& longArray) 129 | { 130 | return JavaConvert::ConvertToJLongArray(longArray); 131 | } 132 | static jfloatArray convertArg(const TArray& floatArray) 133 | { 134 | return JavaConvert::ConvertToJFloatArray(floatArray); 135 | } 136 | 137 | 138 | ///=============== Override Tempalte=========================== 139 | static std::string GetTypeName(void) 140 | { 141 | return "V"; 142 | } 143 | static std::string GetTypeName(bool) 144 | { 145 | return "Z"; 146 | } 147 | static std::string GetTypeName(unsigned char) 148 | { 149 | return "B"; 150 | } 151 | static std::string GetTypeName(char) 152 | { 153 | return "C"; 154 | } 155 | static std::string GetTypeName(short) 156 | { 157 | return "S"; 158 | } 159 | static std::string GetTypeName(int) 160 | { 161 | return "I"; 162 | } 163 | static std::string GetTypeName(unsigned int) 164 | { 165 | return "I"; 166 | } 167 | static std::string GetTypeName(long) 168 | { 169 | return "J"; 170 | } 171 | static std::string GetTypeName(float) 172 | { 173 | return "F"; 174 | } 175 | static std::string GetTypeName(double) 176 | { 177 | return "D"; 178 | } 179 | static std::string GetTypeName(const char*) 180 | { 181 | return "Ljava/lang/String;"; 182 | } 183 | static std::string GetTypeName(const std::string&) 184 | { 185 | return "Ljava/lang/String;"; 186 | } 187 | static std::string GetTypeName(const FString&) 188 | { 189 | return "Ljava/lang/String;"; 190 | } 191 | static std::string GetTypeName(jstring) 192 | { 193 | return "Ljava/lang/String;"; 194 | } 195 | static std::string GetTypeName(jobject) 196 | { 197 | return "Ljava/lang/Object;"; 198 | } 199 | 200 | //----array 201 | static std::string GetTypeName(jobjectArray) 202 | { 203 | return "[Ljava/lang/Object;"; 204 | } 205 | template 206 | static std::string GetTypeName(const TArray&) 207 | { 208 | anyType SymbolType{}; 209 | return std::string("[" + GetTypeName(SymbolType)); 210 | } 211 | template 212 | static std::string GetTypeName(const vector&) 213 | { 214 | anyType SymbolType{}; 215 | return std::string("[" + GetTypeName(SymbolType)); 216 | } 217 | 218 | 219 | ///=============== Recursion Method for Variadic Template=========================== 220 | // ------------ GetType 221 | template 222 | static void GetType(std::string& signatureString, anyType value, Args ...args) 223 | { 224 | signatureString += GetTypeName(value); 225 | GetType(signatureString, args...); 226 | } 227 | // ------------ GetType 228 | static void GetType(std::string&) { } 229 | 230 | 231 | ///=============== Call Target Jni ======================================== 232 | //========== UserObjectClass ============== 233 | static void CallJniVoidMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 234 | { 235 | if (!m_supportedPlatform) 236 | return; 237 | 238 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallJniVoidMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 239 | 240 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 241 | jclass Class = FAndroidApplication::FindJavaClass(ClassName); 242 | #if UE_BUILD_SHIPPING 243 | if (!Class) return; 244 | #endif 245 | jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false); 246 | #if UE_BUILD_SHIPPING 247 | if (!Method) return; 248 | #endif 249 | 250 | va_list Args; 251 | va_start(Args, MethodSignature); 252 | Env->CallStaticVoidMethodV(Class, Method, Args); 253 | va_end(Args); 254 | 255 | Env->DeleteLocalRef(Class); 256 | } 257 | 258 | static FString CallJniStringMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 259 | { 260 | if (!m_supportedPlatform) 261 | return TEXT(""); 262 | 263 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallJniStringMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 264 | 265 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 266 | jclass Class = FAndroidApplication::FindJavaClass(ClassName); 267 | #if UE_BUILD_SHIPPING 268 | if (!Class) return TEXT(""); 269 | #endif 270 | jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false); 271 | #if UE_BUILD_SHIPPING 272 | if (!Method) return TEXT(""); 273 | #endif 274 | 275 | va_list Args; 276 | va_start(Args, MethodSignature); 277 | jstring Return = static_cast(Env->CallStaticObjectMethodV(Class, Method, Args)); 278 | va_end(Args); 279 | 280 | const char* UTFString = Env->GetStringUTFChars(Return, nullptr); 281 | FString Result(UTF8_TO_TCHAR(UTFString)); 282 | Env->ReleaseStringUTFChars(Return, UTFString); 283 | Env->DeleteLocalRef(Class); 284 | 285 | return Result; 286 | } 287 | static bool CallJniBoolMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 288 | { 289 | if (!m_supportedPlatform) 290 | return false; 291 | 292 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallJniBoolMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 293 | 294 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 295 | jclass Class = FAndroidApplication::FindJavaClass(ClassName); 296 | #if UE_BUILD_SHIPPING 297 | if (!Class) return false; 298 | #endif 299 | jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false); 300 | #if UE_BUILD_SHIPPING 301 | if (!Method) return false; 302 | #endif 303 | 304 | va_list Args; 305 | va_start(Args, MethodSignature); 306 | bool Result = Env->CallStaticBooleanMethodV(Class, Method, Args); 307 | va_end(Args); 308 | 309 | Env->DeleteLocalRef(Class); 310 | 311 | return Result; 312 | } 313 | static int CallJniIntMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 314 | { 315 | if (!m_supportedPlatform) 316 | return 0; 317 | 318 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallJniIntMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 319 | 320 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 321 | jclass Class = FAndroidApplication::FindJavaClass(ClassName); 322 | #if UE_BUILD_SHIPPING 323 | if (!Class) return 0; 324 | #endif 325 | jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false); 326 | #if UE_BUILD_SHIPPING 327 | if (!Method) return 0; 328 | #endif 329 | 330 | va_list Args; 331 | va_start(Args, MethodSignature); 332 | int Result = Env->CallStaticIntMethodV(Class, Method, Args); 333 | va_end(Args); 334 | 335 | Env->DeleteLocalRef(Class); 336 | 337 | return Result; 338 | } 339 | static long CallJniLongMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 340 | { 341 | if (!m_supportedPlatform) 342 | return 0; 343 | 344 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallJniLongMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 345 | 346 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 347 | jclass Class = FAndroidApplication::FindJavaClass(ClassName); 348 | #if UE_BUILD_SHIPPING 349 | if (!Class) return 0; 350 | #endif 351 | jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false); 352 | #if UE_BUILD_SHIPPING 353 | if (!Method) return 0; 354 | #endif 355 | 356 | va_list Args; 357 | va_start(Args, MethodSignature); 358 | long Result = Env->CallStaticLongMethodV(Class, Method, Args); 359 | va_end(Args); 360 | 361 | Env->DeleteLocalRef(Class); 362 | 363 | return Result; 364 | } 365 | static jobject CallJniObjectMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 366 | { 367 | if (!m_supportedPlatform) 368 | return nullptr; 369 | 370 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallJniObjectMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 371 | 372 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 373 | jclass Class = FAndroidApplication::FindJavaClass(ClassName); 374 | #if UE_BUILD_SHIPPING 375 | if (!Class) return nullptr; 376 | #endif 377 | jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false); 378 | #if UE_BUILD_SHIPPING 379 | if (!Method) return nullptr; 380 | #endif 381 | 382 | va_list Args; 383 | va_start(Args, MethodSignature); 384 | jobject Result = Env->CallStaticObjectMethodV(Class, Method, Args); 385 | va_end(Args); 386 | 387 | Env->DeleteLocalRef(Class); 388 | if (!Result) 389 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 390 | 391 | 392 | return Result; 393 | } 394 | static jobjectArray CallJniObjectArrayMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 395 | { 396 | if (!m_supportedPlatform) 397 | return nullptr; 398 | 399 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallJniObjectArray [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 400 | 401 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 402 | jclass Class = FAndroidApplication::FindJavaClass(ClassName); 403 | #if UE_BUILD_SHIPPING 404 | if (!Class) return nullptr; 405 | #endif 406 | jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false); 407 | #if UE_BUILD_SHIPPING 408 | if (!Method) return nullptr; 409 | #endif 410 | 411 | va_list Args; 412 | va_start(Args, MethodSignature); 413 | jobjectArray Result = static_cast(Env->CallStaticObjectMethodV(Class, Method, Args)); 414 | va_end(Args); 415 | 416 | Env->DeleteLocalRef(Class); 417 | if (!Result) 418 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobjectArray = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 419 | 420 | return Result; 421 | } 422 | static jfloatArray CallJniFloatArrayMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 423 | { 424 | if (!m_supportedPlatform) 425 | return nullptr; 426 | 427 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallJniFloatArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 428 | 429 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 430 | jclass Class = FAndroidApplication::FindJavaClass(ClassName); 431 | #if UE_BUILD_SHIPPING 432 | if (!Class) return nullptr; 433 | #endif 434 | jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false); 435 | #if UE_BUILD_SHIPPING 436 | if (!Method) return nullptr; 437 | #endif 438 | 439 | va_list Args; 440 | va_start(Args, MethodSignature); 441 | jfloatArray Result = static_cast(Env->CallStaticObjectMethodV(Class, Method, Args)); 442 | va_end(Args); 443 | 444 | Env->DeleteLocalRef(Class); 445 | 446 | return Result; 447 | } 448 | static jintArray CallJniIntArrayMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 449 | { 450 | if (!m_supportedPlatform) 451 | return nullptr; 452 | 453 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallJniIntArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 454 | 455 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 456 | jclass Class = FAndroidApplication::FindJavaClass(ClassName); 457 | #if UE_BUILD_SHIPPING 458 | if (!Class) return nullptr; 459 | #endif 460 | jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false); 461 | #if UE_BUILD_SHIPPING 462 | if (!Method) return nullptr; 463 | #endif 464 | 465 | va_list Args; 466 | va_start(Args, MethodSignature); 467 | jintArray Result = static_cast(Env->CallStaticObjectMethodV(Class, Method, Args)); 468 | va_end(Args); 469 | 470 | Env->DeleteLocalRef(Class); 471 | 472 | return Result; 473 | } 474 | static jlongArray CallJniLongArrayMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 475 | { 476 | if (!m_supportedPlatform) 477 | return nullptr; 478 | 479 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallJniLongArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 480 | 481 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 482 | jclass Class = FAndroidApplication::FindJavaClass(ClassName); 483 | #if UE_BUILD_SHIPPING 484 | if (!Class) return nullptr; 485 | #endif 486 | jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false); 487 | #if UE_BUILD_SHIPPING 488 | if (!Method) return nullptr; 489 | #endif 490 | 491 | va_list Args; 492 | va_start(Args, MethodSignature); 493 | jlongArray Result = static_cast(Env->CallStaticObjectMethodV(Class, Method, Args)); 494 | va_end(Args); 495 | 496 | Env->DeleteLocalRef(Class); 497 | 498 | return Result; 499 | } 500 | 501 | //========== JavaObjectClass ============== 502 | static void CallObjectJniVoidMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 503 | { 504 | if (!m_supportedPlatform) 505 | return; 506 | 507 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallObjectJniVoidMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 508 | if (!object) 509 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 510 | 511 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 512 | jclass Class = Env->GetObjectClass(object); 513 | #if UE_BUILD_SHIPPING 514 | if (!Class) return; 515 | #endif 516 | jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false); 517 | #if UE_BUILD_SHIPPING 518 | if (!Method) return; 519 | #endif 520 | 521 | va_list Args; 522 | va_start(Args, MethodSignature); 523 | Env->CallVoidMethodV(object, Method, Args); 524 | va_end(Args); 525 | 526 | Env->DeleteLocalRef(Class); 527 | } 528 | 529 | static FString CallObjectJniStringMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 530 | { 531 | if (!m_supportedPlatform) 532 | return TEXT(""); 533 | 534 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallObjectJniStringMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 535 | if (!object) 536 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 537 | 538 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 539 | jclass Class = Env->GetObjectClass(object); 540 | #if UE_BUILD_SHIPPING 541 | if (!Class) return TEXT(""); 542 | #endif 543 | jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false); 544 | #if UE_BUILD_SHIPPING 545 | if (!Method) return TEXT(""); 546 | #endif 547 | 548 | va_list Args; 549 | va_start(Args, MethodSignature); 550 | jstring Return = static_cast(Env->CallObjectMethodV(object, Method, Args)); 551 | va_end(Args); 552 | 553 | const char* UTFString = Env->GetStringUTFChars(Return, nullptr); 554 | FString Result(UTF8_TO_TCHAR(UTFString)); 555 | Env->ReleaseStringUTFChars(Return, UTFString); 556 | 557 | Env->DeleteLocalRef(Class); 558 | 559 | return Result; 560 | } 561 | static bool CallObjectJniBoolMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 562 | { 563 | if (!m_supportedPlatform) 564 | return false; 565 | 566 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallObjectJniBoolMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 567 | if (!object) 568 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 569 | 570 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 571 | jclass Class = Env->GetObjectClass(object); 572 | #if UE_BUILD_SHIPPING 573 | if (!Class) return false; 574 | #endif 575 | jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false); 576 | #if UE_BUILD_SHIPPING 577 | if (!Method) return false; 578 | #endif 579 | 580 | va_list Args; 581 | va_start(Args, MethodSignature); 582 | bool Result = Env->CallBooleanMethodV(object, Method, Args); 583 | va_end(Args); 584 | 585 | Env->DeleteLocalRef(Class); 586 | 587 | return Result; 588 | } 589 | static int CallObjectJniIntMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 590 | { 591 | if (!m_supportedPlatform) 592 | return 0; 593 | 594 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallObjectJniIntMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 595 | if (!object) 596 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 597 | 598 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 599 | jclass Class = Env->GetObjectClass(object); 600 | #if UE_BUILD_SHIPPING 601 | if (!Class) return 0; 602 | #endif 603 | jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false); 604 | #if UE_BUILD_SHIPPING 605 | if (!Method) return 0; 606 | #endif 607 | 608 | va_list Args; 609 | va_start(Args, MethodSignature); 610 | int Result = Env->CallIntMethodV(object, Method, Args); 611 | va_end(Args); 612 | 613 | Env->DeleteLocalRef(Class); 614 | 615 | return Result; 616 | } 617 | static long CallObjectJniLongMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 618 | { 619 | if (!m_supportedPlatform) 620 | return 0; 621 | 622 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallObjectJniLongMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 623 | if (!object) 624 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 625 | 626 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 627 | jclass Class = Env->GetObjectClass(object); 628 | #if UE_BUILD_SHIPPING 629 | if (!Class) return 0; 630 | #endif 631 | jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false); 632 | #if UE_BUILD_SHIPPING 633 | if (!Method) return 0; 634 | #endif 635 | 636 | va_list Args; 637 | va_start(Args, MethodSignature); 638 | long Result = Env->CallLongMethodV(object, Method, Args); 639 | va_end(Args); 640 | 641 | Env->DeleteLocalRef(Class); 642 | 643 | return Result; 644 | } 645 | static jobject CallObjectJniObjectMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 646 | { 647 | if (!m_supportedPlatform) 648 | return nullptr; 649 | 650 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallObjectJniObjectMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 651 | if (!object) 652 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 653 | 654 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 655 | jclass Class = Env->GetObjectClass(object); 656 | #if UE_BUILD_SHIPPING 657 | if (!Class) return nullptr; 658 | #endif 659 | jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false); 660 | #if UE_BUILD_SHIPPING 661 | if (!Method) return nullptr; 662 | #endif 663 | 664 | va_list Args; 665 | va_start(Args, MethodSignature); 666 | jobject Result = Env->CallObjectMethodV(object, Method, Args); 667 | va_end(Args); 668 | 669 | Env->DeleteLocalRef(Class); 670 | 671 | if (!Result) 672 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: return jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 673 | 674 | return Result; 675 | } 676 | static jobjectArray CallObjectJniObjectArrayMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 677 | { 678 | if (!m_supportedPlatform) 679 | return nullptr; 680 | 681 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallObjectJniObjectArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 682 | if (!object) 683 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 684 | 685 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 686 | jclass Class = Env->GetObjectClass(object); 687 | #if UE_BUILD_SHIPPING 688 | if (!Class) return nullptr; 689 | #endif 690 | jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false); 691 | #if UE_BUILD_SHIPPING 692 | if (!Method) return nullptr; 693 | #endif 694 | 695 | va_list Args; 696 | va_start(Args, MethodSignature); 697 | jobjectArray Result = static_cast(Env->CallObjectMethodV(object, Method, Args)); 698 | va_end(Args); 699 | 700 | Env->DeleteLocalRef(Class); 701 | if (!Result) 702 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: return jobjectArray = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 703 | 704 | return Result; 705 | } 706 | static jfloatArray CallObjectJniFloatArrayMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 707 | { 708 | if (!m_supportedPlatform) 709 | return nullptr; 710 | 711 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallObjectJniFloatArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 712 | if (!object) 713 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 714 | 715 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 716 | jclass Class = Env->GetObjectClass(object); 717 | #if UE_BUILD_SHIPPING 718 | if (!Class) return nullptr; 719 | #endif 720 | jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false); 721 | #if UE_BUILD_SHIPPING 722 | if (!Method) return nullptr; 723 | #endif 724 | 725 | va_list Args; 726 | va_start(Args, MethodSignature); 727 | jfloatArray Result = static_cast(Env->CallObjectMethodV(object, Method, Args)); 728 | va_end(Args); 729 | 730 | Env->DeleteLocalRef(Class); 731 | 732 | return Result; 733 | } 734 | static jintArray CallObjectJniIntArrayMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 735 | { 736 | if (!m_supportedPlatform) 737 | return nullptr; 738 | 739 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallObjectJniIntArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 740 | if (!object) 741 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 742 | 743 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 744 | jclass Class = Env->GetObjectClass(object); 745 | #if UE_BUILD_SHIPPING 746 | if (!Class) return nullptr; 747 | #endif 748 | jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false); 749 | #if UE_BUILD_SHIPPING 750 | if (!Method) return nullptr; 751 | #endif 752 | 753 | va_list Args; 754 | va_start(Args, MethodSignature); 755 | jintArray Result = static_cast(Env->CallObjectMethodV(object, Method, Args)); 756 | va_end(Args); 757 | 758 | Env->DeleteLocalRef(Class); 759 | 760 | return Result; 761 | } 762 | static jlongArray CallObjectJniLongArrayMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...) 763 | { 764 | if (!m_supportedPlatform) 765 | return nullptr; 766 | 767 | UE_LOG(LogTemp, Log, TEXT("MobileNativeCode -> Method CallObjectJniLongArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 768 | 769 | if (!object) 770 | UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature)); 771 | 772 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 773 | jclass Class = Env->GetObjectClass(object); 774 | #if UE_BUILD_SHIPPING 775 | if (!Class) return nullptr; 776 | #endif 777 | jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false); 778 | #if UE_BUILD_SHIPPING 779 | if (!Method) return nullptr; 780 | #endif 781 | 782 | va_list Args; 783 | va_start(Args, MethodSignature); 784 | jlongArray Result = static_cast(Env->CallObjectMethodV(object, Method, Args)); 785 | va_end(Args); 786 | 787 | Env->DeleteLocalRef(Class); 788 | 789 | return Result; 790 | } 791 | 792 | 793 | ///=============== Override Callback and Return JNI=========================== 794 | //========== UserObjectClass ============== 795 | 796 | // ------------ void case 797 | template 798 | static void isTypeJNI(type, const char* ClassName, const char* FunctionName, std::string OverrideSignature, bool isActivity, Args ...args) 799 | { 800 | std::string MethodSignature; 801 | if (OverrideSignature.empty()) { 802 | MethodSignature = "("; 803 | MethodSignature += isActivity ? "Landroid/app/Activity;" : ""; 804 | GetType(MethodSignature, args...); 805 | MethodSignature += ")"; 806 | MethodSignature += GetTypeName(); 807 | } 808 | else 809 | { 810 | MethodSignature = OverrideSignature; 811 | } 812 | 813 | if (isActivity) 814 | CallJniVoidMethod(ClassName, FunctionName, MethodSignature.c_str(), FJavaWrapper::GameActivityThis, convertArg(args)...); 815 | else 816 | CallJniVoidMethod(ClassName, FunctionName, MethodSignature.c_str(), convertArg(args)...); 817 | } 818 | 819 | // ------------ non-void case 820 | template 821 | static MethodType isTypeJNI(type, const char* ClassName, const char* FunctionName, std::string OverrideSignature, bool isActivity, Args ...args) 822 | { 823 | MethodType returnType{}; 824 | 825 | std::string MethodSignature; 826 | if (OverrideSignature.empty()) { 827 | MethodSignature = "("; 828 | MethodSignature += isActivity ? "Landroid/app/Activity;" : ""; 829 | GetType(MethodSignature, args...); 830 | MethodSignature += ")"; 831 | MethodSignature += GetTypeName(returnType); 832 | } 833 | else 834 | { 835 | MethodSignature = OverrideSignature; 836 | } 837 | 838 | if (isActivity) 839 | return CallJNI(returnType, ClassName, FunctionName, MethodSignature.c_str(), FJavaWrapper::GameActivityThis, convertArg(args)...); 840 | else 841 | return CallJNI(returnType, ClassName, FunctionName, MethodSignature.c_str(), convertArg(args)...); 842 | } 843 | 844 | // ------------ FString 845 | template 846 | static FString CallJNI(const FString&, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 847 | { 848 | return CallJniStringMethod(ClassName, MethodName, MethodSignature, args...); 849 | } 850 | // ------------ std::string 851 | template 852 | static std::string CallJNI(const std::string&, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 853 | { 854 | FString TempStr = CallJniStringMethod(ClassName, MethodName, MethodSignature, args...); 855 | return std::string(TCHAR_TO_UTF8(*TempStr)); 856 | } 857 | // ------------ bool 858 | template 859 | static bool CallJNI(bool, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 860 | { 861 | return CallJniBoolMethod(ClassName, MethodName, MethodSignature, args...); 862 | } 863 | // ------------ int 864 | template 865 | static int CallJNI(int, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 866 | { 867 | return CallJniIntMethod(ClassName, MethodName, MethodSignature, args...); 868 | } 869 | // ------------ long 870 | template 871 | static long CallJNI(long, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 872 | { 873 | return CallJniLongMethod(ClassName, MethodName, MethodSignature, args...); 874 | } 875 | // ------------ jobject 876 | template 877 | static jobject CallJNI(jobject, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 878 | { 879 | return CallJniObjectMethod(ClassName, MethodName, MethodSignature, args...); 880 | } 881 | // ------------ jobjectArray 882 | template 883 | static jobjectArray CallJNI(jobjectArray, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 884 | { 885 | return CallJniObjectArrayMethod(ClassName, MethodName, MethodSignature, args...); 886 | } 887 | // ------------ TArray 888 | template 889 | static TArray CallJNI(const TArray&, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 890 | { 891 | return JavaConvert::ConvertToStringArray(CallJniObjectArrayMethod(ClassName, MethodName, MethodSignature, args...)); 892 | } 893 | // ------------ TArray 894 | template 895 | static TArray CallJNI(const TArray&, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 896 | { 897 | return JavaConvert::ConvertToFloatArray(CallJniFloatArrayMethod(ClassName, MethodName, MethodSignature, args...)); 898 | } 899 | // ------------ TArray 900 | template 901 | static TArray CallJNI(const TArray&, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 902 | { 903 | return JavaConvert::ConvertToIntArray(CallJniIntArrayMethod(ClassName, MethodName, MethodSignature, args...)); 904 | } 905 | // ------------ TArray 906 | template 907 | static TArray CallJNI(const TArray&, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args) 908 | { 909 | return JavaConvert::ConvertToLongArray(CallJniLongArrayMethod(ClassName, MethodName, MethodSignature, args...)); 910 | } 911 | 912 | 913 | //========== JavaObjectClass ============== 914 | 915 | // ------------ void case object 916 | template 917 | static void isTypeJNI(type, jobject JavaObjectClass, const char* FunctionName, std::string OverrideSignature, Args ...args) 918 | { 919 | std::string MethodSignature; 920 | if (OverrideSignature.empty()) { 921 | MethodSignature = "("; 922 | GetType(MethodSignature, args...); 923 | MethodSignature += ")"; 924 | MethodSignature += GetTypeName(); 925 | } 926 | else 927 | { 928 | MethodSignature = OverrideSignature; 929 | } 930 | 931 | CallObjectJniVoidMethod(JavaObjectClass, FunctionName, MethodSignature.c_str(), convertArg(args)...); 932 | } 933 | 934 | // ------------ non-void case object 935 | template 936 | static MethodType isTypeJNI(type, jobject JavaObjectClass, const char* FunctionName, std::string OverrideSignature, Args ...args) 937 | { 938 | MethodType returnType{}; 939 | 940 | std::string MethodSignature; 941 | if (OverrideSignature.empty()) { 942 | MethodSignature = "("; 943 | GetType(MethodSignature, args...); 944 | MethodSignature += ")"; 945 | MethodSignature += GetTypeName(returnType); 946 | } 947 | else 948 | { 949 | MethodSignature = OverrideSignature; 950 | } 951 | 952 | return CallObjectJNI(returnType, JavaObjectClass, FunctionName, MethodSignature.c_str(), convertArg(args)...); 953 | } 954 | 955 | // ------------ FString 956 | template 957 | static FString CallObjectJNI(const FString&, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 958 | { 959 | return CallObjectJniStringMethod(JavaObjectClass, MethodName, MethodSignature, args...); 960 | } 961 | // ------------ std::string 962 | template 963 | static std::string CallObjectJNI(const std::string&, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 964 | { 965 | FString TempStr = CallObjectJniStringMethod(JavaObjectClass, MethodName, MethodSignature, args...); 966 | return std::string(TCHAR_TO_UTF8(*TempStr)); 967 | } 968 | // ------------ bool 969 | template 970 | static bool CallObjectJNI(bool, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 971 | { 972 | return CallObjectJniBoolMethod(JavaObjectClass, MethodName, MethodSignature, args...); 973 | } 974 | // ------------ int 975 | template 976 | static int CallObjectJNI(int, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 977 | { 978 | return CallObjectJniIntMethod(JavaObjectClass, MethodName, MethodSignature, args...); 979 | } 980 | // ------------ long 981 | template 982 | static long CallObjectJNI(long, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 983 | { 984 | return CallObjectJniLongMethod(JavaObjectClass, MethodName, MethodSignature, args...); 985 | } 986 | // ------------ jobject 987 | template 988 | static jobject CallObjectJNI(jobject, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 989 | { 990 | return CallObjectJniObjectMethod(JavaObjectClass, MethodName, MethodSignature, args...); 991 | } 992 | // ------------ jobjectArray 993 | template 994 | static jobjectArray CallObjectJNI(jobjectArray, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 995 | { 996 | return CallObjectJniObjectArrayMethod(JavaObjectClass, MethodName, MethodSignature, args...); 997 | } 998 | // ------------ TArray 999 | template 1000 | static TArray CallObjectJNI(const TArray&, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 1001 | { 1002 | return JavaConvert::ConvertToStringArray(CallObjectJniObjectArrayMethod(JavaObjectClass, MethodName, MethodSignature, args...)); 1003 | } 1004 | // ------------ TArray 1005 | template 1006 | static TArray CallObjectJNI(const TArray&, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 1007 | { 1008 | return JavaConvert::ConvertToFloatArray(CallObjectJniFloatArrayMethod(JavaObjectClass, MethodName, MethodSignature, args...)); 1009 | } 1010 | // ------------ TArray 1011 | template 1012 | static TArray CallObjectJNI(const TArray&, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 1013 | { 1014 | return JavaConvert::ConvertToIntArray(CallObjectJniIntArrayMethod(JavaObjectClass, MethodName, MethodSignature, args...)); 1015 | } 1016 | // ------------ TArray 1017 | template 1018 | static TArray CallObjectJNI(const TArray&, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args) 1019 | { 1020 | return JavaConvert::ConvertToLongArray(CallObjectJniLongArrayMethod(JavaObjectClass, MethodName, MethodSignature, args...)); 1021 | } 1022 | 1023 | 1024 | ///============Calling native Android code from C++=============== 1025 | 1026 | /** 1027 | * @param ClassName - package and the name of your Java class. 1028 | * @param FunctionName - Name of your Java function. 1029 | * @param OverrideSignature - Set your own signature instead of an automatic one (Send an empty one if you need an automatic one). 1030 | * @param isActivity - Determines whether to pass Activity UE4 to Java. 1031 | * @param args... - A list of your parameters in the Java function. 1032 | */ 1033 | template 1034 | static MethodType CallJavaCode(const char* ClassName, const char* FunctionName, const char* OverrideSignature, bool isActivity, Args ...args) 1035 | { 1036 | return isTypeJNI(type{}, ClassName, FunctionName, OverrideSignature, isActivity, args...); 1037 | } 1038 | 1039 | /** 1040 | * @param JavaObjectClass - The object type which you need to call methods from the JAVA API. 1041 | * @param FunctionName - Name of your Java function. 1042 | * @param OverrideSignature - Set your own signature instead of an automatic one (Send an empty one if you need an automatic one). 1043 | * @param args... - A list of your parameters in the Java function. 1044 | */ 1045 | template 1046 | static MethodType CallJavaCode(jobject JavaObjectClass, const char* FunctionName, const char* OverrideSignature, Args ...args) 1047 | { 1048 | return isTypeJNI(type{}, JavaObjectClass, FunctionName, OverrideSignature, args...); 1049 | } 1050 | 1051 | }; 1052 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Utils/JavaConvert.cpp: -------------------------------------------------------------------------------- 1 | #include "JavaConvert.h" 2 | 3 | //==============Java Convert=================================== 4 | 5 | // TArray to jobjectArray 6 | jobjectArray JavaConvert::ConvertToJStringArray(const TArray& stringArray) 7 | { 8 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 9 | jobjectArray javaStringArray = Env->NewObjectArray(stringArray.Num(), FJavaWrapper::JavaStringClass, nullptr); 10 | for(int i = 0; i < stringArray.Num(); i++) 11 | { 12 | Env->SetObjectArrayElement(javaStringArray, i, JavaConvert::GetJavaString(stringArray[i])); 13 | } 14 | return javaStringArray; 15 | } 16 | 17 | // TArray to jbooleanArray 18 | jbooleanArray JavaConvert::ConvertToJBooleanArray(const TArray& boolArray) 19 | { 20 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 21 | jbooleanArray javaBooleanArray = Env->NewBooleanArray(boolArray.Num()); 22 | jboolean* javaBooleanArrayPtr = Env->GetBooleanArrayElements(javaBooleanArray, 0); 23 | for(int i = 0; i < boolArray.Num(); i++) 24 | { 25 | javaBooleanArrayPtr[i] = boolArray[i]; 26 | } 27 | return javaBooleanArray; 28 | } 29 | 30 | // TArray to jintArray 31 | jintArray JavaConvert::ConvertToJIntArray(const TArray& intArray) 32 | { 33 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 34 | jintArray javaIntArray = Env->NewIntArray(intArray.Num()); 35 | jint* javaIntArrayPtr = (jint*)malloc(intArray.Num() * sizeof(jint)); 36 | for(int i = 0; i < intArray.Num(); i++) 37 | { 38 | javaIntArrayPtr[i] = (jint)intArray[i]; 39 | } 40 | Env->SetIntArrayRegion(javaIntArray, 0, intArray.Num(), javaIntArrayPtr); 41 | free(javaIntArrayPtr); 42 | return javaIntArray; 43 | } 44 | 45 | // TArray to jbyteArray 46 | jbyteArray JavaConvert::ConvertToJByteArray(const TArray& byteArray) 47 | { 48 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 49 | jbyteArray javaByteArray = Env->NewByteArray(byteArray.Num()); 50 | jbyte* javaByteArrayPtr = (jbyte*)malloc(byteArray.Num() * sizeof(jbyte)); 51 | for(int i = 0; i < byteArray.Num(); i++) 52 | { 53 | javaByteArrayPtr[i] = byteArray[i]; 54 | } 55 | Env->SetByteArrayRegion(javaByteArray, 0, byteArray.Num(), javaByteArrayPtr); 56 | free(javaByteArrayPtr); 57 | return javaByteArray; 58 | } 59 | 60 | // TArray to jlongArray 61 | jlongArray JavaConvert::ConvertToJLongArray(const TArray& longArray) 62 | { 63 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 64 | jlongArray javaLongArray = Env->NewLongArray(longArray.Num()); 65 | jlong* javaLongArrayPtr = (jlong*)malloc(longArray.Num() * sizeof(jlong)); 66 | for(int i = 0; i < longArray.Num(); i++) 67 | { 68 | javaLongArrayPtr[i] = longArray[i]; 69 | } 70 | Env->SetLongArrayRegion(javaLongArray, 0, longArray.Num(), javaLongArrayPtr); 71 | free(javaLongArrayPtr); 72 | return javaLongArray; 73 | } 74 | 75 | // TArray to jfloatArray 76 | jfloatArray JavaConvert::ConvertToJFloatArray(const TArray& floatArray) 77 | { 78 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 79 | jfloatArray javaFloatArray = Env->NewFloatArray(floatArray.Num()); 80 | jfloat* javaFloatArrayPtr = (jfloat*)malloc(floatArray.Num() * sizeof(jfloat)); 81 | for(int i = 0; i < floatArray.Num(); i++) 82 | { 83 | javaFloatArrayPtr[i] = floatArray[i]; 84 | } 85 | Env->SetFloatArrayRegion(javaFloatArray, 0, floatArray.Num(), javaFloatArrayPtr); 86 | free(javaFloatArrayPtr); 87 | return javaFloatArray; 88 | } 89 | 90 | // jbyteArray to TArray 91 | TArray JavaConvert::ConvertToByteArray(jbyteArray javaArray) 92 | { 93 | TArray byteArray; 94 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 95 | jbyte* javaByte = Env->GetByteArrayElements(javaArray, 0); 96 | int length = Env->GetArrayLength(javaArray); 97 | for(int i = 0; i < length; i++) 98 | { 99 | byteArray.Add(javaByte[i]); 100 | } 101 | return byteArray; 102 | } 103 | 104 | // jfloatArray to TArray 105 | TArray JavaConvert::ConvertToFloatArray(jfloatArray javaArray) 106 | { 107 | TArray floatArray; 108 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 109 | jfloat* javaFloat = Env->GetFloatArrayElements(javaArray, 0); 110 | int length = Env->GetArrayLength(javaArray); 111 | for(int i = 0; i < length; i++) 112 | { 113 | floatArray.Add((float)javaFloat[i]); 114 | } 115 | return floatArray; 116 | } 117 | 118 | // jintArray to TArray 119 | TArray JavaConvert::ConvertToIntArray(jintArray javaArray) 120 | { 121 | TArray numArray; 122 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 123 | jint* javaNum = Env->GetIntArrayElements(javaArray, 0); 124 | int length = Env->GetArrayLength(javaArray); 125 | for(int i = 0; i < length; i++) 126 | { 127 | numArray.Add((int)javaNum[i]); 128 | } 129 | return numArray; 130 | } 131 | 132 | // jlongArray to TArray 133 | TArray JavaConvert::ConvertToLongArray(jlongArray javaArray) 134 | { 135 | TArray longArray; 136 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 137 | jlong* javaLong = Env->GetLongArrayElements(javaArray, 0); 138 | int length = Env->GetArrayLength(javaArray); 139 | for(int i = 0; i < length; i++) 140 | { 141 | longArray.Add((long)javaLong[i]); 142 | } 143 | return longArray; 144 | } 145 | 146 | // jobjectArray to TArray 147 | TArray JavaConvert::ConvertToStringArray(jobjectArray javaStringArray) 148 | { 149 | TArray stringArray; 150 | JNIEnv* Env = FAndroidApplication::GetJavaEnv(); 151 | int length = Env->GetArrayLength(javaStringArray); 152 | for(int i = 0; i < length; i++) 153 | { 154 | jstring javaString = static_cast(Env->GetObjectArrayElement(javaStringArray, i)); 155 | 156 | stringArray.Add(JavaConvert::FromJavaFString(javaString)); 157 | } 158 | 159 | return stringArray; 160 | } 161 | 162 | // long to jlong 163 | jlong JavaConvert::GetJavaLong(long l) 164 | { 165 | jlong jl = static_cast(l); 166 | return jl; 167 | } 168 | 169 | // FString to jstring 170 | jstring JavaConvert::GetJavaString(const FString& string) 171 | { 172 | return GetJavaString(TCHAR_TO_UTF8(*string)); 173 | } 174 | 175 | // string to jstring 176 | jstring JavaConvert::GetJavaString(const string& str) 177 | { 178 | return GetJavaString(str.c_str()); 179 | } 180 | 181 | // const char* to jstring 182 | jstring JavaConvert::GetJavaString(const char* str) 183 | { 184 | JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv(); 185 | return JEnv->NewStringUTF(str); 186 | } 187 | 188 | // jstring to FString 189 | FString JavaConvert::FromJavaFString(jstring javaString) 190 | { 191 | JNIEnv* Env = AndroidJavaEnv::GetJavaEnv(); 192 | const char* UTFString = Env->GetStringUTFChars(javaString, nullptr); 193 | FString Result(UTF8_TO_TCHAR(UTFString)); 194 | Env->ReleaseStringUTFChars(javaString, UTFString); 195 | Env->DeleteLocalRef(javaString); 196 | 197 | return Result; 198 | } 199 | 200 | // jstring to string 201 | string JavaConvert::FromJavaString(jstring javaString) 202 | { 203 | JNIEnv* Env = AndroidJavaEnv::GetJavaEnv(); 204 | const char* UTFString = Env->GetStringUTFChars(javaString, nullptr); 205 | FString Result(UTF8_TO_TCHAR(UTFString)); 206 | Env->ReleaseStringUTFChars(javaString, UTFString); 207 | Env->DeleteLocalRef(javaString); 208 | 209 | return string(TCHAR_TO_UTF8(*Result)); 210 | } 211 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/Android/Utils/JavaConvert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | 13 | 14 | class JavaConvert 15 | { 16 | public: 17 | //======= Functions for converting to Java types ================== 18 | 19 | // TArray to jobjectArray 20 | static jobjectArray ConvertToJStringArray(const TArray& stringArray); 21 | 22 | // TArray to jbooleanArray 23 | static jbooleanArray ConvertToJBooleanArray(const TArray& boolArray); 24 | 25 | // TArray to jintArray 26 | static jintArray ConvertToJIntArray(const TArray& intArray); 27 | 28 | // TArray to jbyteArray 29 | static jbyteArray ConvertToJByteArray(const TArray& byteArray); 30 | 31 | // TArray to jlongArray 32 | static jlongArray ConvertToJLongArray(const TArray& longArray); 33 | 34 | // TArray to jfloatArray 35 | static jfloatArray ConvertToJFloatArray(const TArray& floatArray); 36 | 37 | // jbyteArray to TArray 38 | static TArray ConvertToByteArray(jbyteArray javaArray); 39 | 40 | // jfloatArray to TArray 41 | static TArray ConvertToFloatArray(jfloatArray javaArray); 42 | 43 | // jfloatArray to TArray 44 | static TArray ConvertToIntArray(jintArray javaArray); 45 | 46 | // jlongArray to TArray 47 | static TArray ConvertToLongArray(jlongArray javaArray); 48 | 49 | // jobjectArray to TArray 50 | static TArray ConvertToStringArray(jobjectArray javaStringArray); 51 | 52 | // long to jlong 53 | static jlong GetJavaLong(long l); 54 | 55 | // FString to jstring 56 | static jstring GetJavaString(const FString& string); 57 | 58 | // string to jstring 59 | static jstring GetJavaString(const string& str); 60 | 61 | // const char* to jstring 62 | static jstring GetJavaString(const char* str); 63 | 64 | // jstring to FString 65 | static FString FromJavaFString(jstring javaString); 66 | 67 | // jstring to string 68 | static string FromJavaString(jstring javaString); 69 | }; 70 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/IosAsyncHelloWorld.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #import 4 | #import 5 | #import 6 | #import 7 | 8 | 9 | 10 | @interface IosAsyncHelloWorld : NSObject 11 | 12 | +(void)asyncHelloWorldOnIOS: (NSString*)text; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/IosAsyncHelloWorld.mm: -------------------------------------------------------------------------------- 1 | #import "IosAsyncHelloWorld.h" 2 | #include "MobileNativeCodeBlueprint.h" // For Dispatcher UE4 3 | 4 | @implementation IosAsyncHelloWorld 5 | 6 | - (instancetype)init 7 | { 8 | self = [super init]; 9 | return self; 10 | } 11 | 12 | //-- Calling IOS code asynchronously and returning the value back to C++ 13 | + (void) asyncHelloWorldOnIOS:(NSString*)text 14 | { 15 | dispatch_async(dispatch_get_main_queue(), ^{ 16 | NSString* tmpStr = @" on IOS"; 17 | NSString* ReturnText = [text stringByAppendingString: tmpStr]; 18 | UMobileNativeCodeBlueprint::CallBackCppIOS(ReturnText); 19 | }); 20 | } 21 | 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/IosDeviceInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #import 4 | #import 5 | #import 6 | #import 7 | 8 | 9 | @interface IosDeviceInfo : NSObject 10 | 11 | +(NSString*)getModel; 12 | +(NSString*)getTmpFilePath; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/IosDeviceInfo.mm: -------------------------------------------------------------------------------- 1 | #import "IosDeviceInfo.h" 2 | 3 | @implementation IosDeviceInfo 4 | 5 | //-- Device information 6 | + (NSString*)getModel 7 | { 8 | struct utsname systemInfo; 9 | uname(&systemInfo); 10 | 11 | NSString* Model = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; 12 | return Model; 13 | } 14 | 15 | //-- Path to "/var/mobile/Containers/Data/Application/%PROJECT_ID%/Library/Caches/" 16 | + (NSString *)getTmpFilePath 17 | { 18 | NSString* path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 19 | 20 | NSString* tmpStr = @"/"; 21 | NSString* ReturnText = [path stringByAppendingString: tmpStr]; 22 | 23 | return ReturnText; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/IosExampleArray.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #import 4 | #import 5 | #import 6 | #import 7 | 8 | 9 | @interface IosExampleArray : NSObject 10 | 11 | +(NSMutableArray*)TestArray:(NSMutableArray*)text b : (NSMutableArray*)b i : (NSMutableArray*)i f : (NSMutableArray*)f l : (NSMutableArray*)l; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/IosExampleArray.mm: -------------------------------------------------------------------------------- 1 | #import "IosExampleArray.h" 2 | 3 | 4 | @implementation IosExampleArray 5 | 6 | +(NSMutableArray*) TestArray:(NSMutableArray*)text b:(NSMutableArray*)b i:(NSMutableArray*)i f:(NSMutableArray*)f l:(NSMutableArray*)l 7 | { 8 | /* 9 | Some clever manipulations with arrays 10 | */ 11 | 12 | NSMutableArray* ArrStr = [NSMutableArray array]; 13 | [ArrStr addObject:@"string"]; 14 | [ArrStr addObject:@"Array"]; 15 | return ArrStr; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/IosHelloWorld.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #import 4 | #import 5 | #import 6 | #import 7 | 8 | 9 | @interface IosHelloWorld : NSObject 10 | 11 | +(NSString*)HelloWorldOnIOS: (NSString*)text; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/IosHelloWorld.mm: -------------------------------------------------------------------------------- 1 | #import "IosHelloWorld.h" 2 | 3 | 4 | @implementation IosHelloWorld 5 | 6 | //-- Calling IOS code synchronously 7 | + (NSString*) HelloWorldOnIOS:(NSString*)text 8 | { 9 | NSString* tmpStr = @" on IOS"; 10 | NSString* ReturnText = [text stringByAppendingString: tmpStr]; 11 | return ReturnText; 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/IosNativeUI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import 8 | 9 | using namespace std; 10 | 11 | @interface IosNativeUI : UIViewController 12 | 13 | +(IosNativeUI*)Singleton; 14 | 15 | /** 16 | * Calling a pop-up message on IOS 17 | */ 18 | -(void) showToast: (NSString*)message Duration: (int)duration; 19 | 20 | @end // IosNativeUI 21 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/IosNativeUI.mm: -------------------------------------------------------------------------------- 1 | #import "IosNativeUI.h" 2 | 3 | @implementation IosNativeUI 4 | 5 | - (instancetype)init 6 | { 7 | self = [super init]; 8 | return self; 9 | } 10 | 11 | + (IosNativeUI *)Singleton 12 | { 13 | static IosNativeUI *staticIosNativeUI; 14 | static dispatch_once_t once; 15 | dispatch_once(&once, ^{ 16 | staticIosNativeUI = [[self alloc] init]; 17 | }); 18 | return staticIosNativeUI; 19 | } 20 | 21 | -(void)showToast: (NSString*)message 22 | Duration: (int)duration 23 | { 24 | dispatch_async(dispatch_get_main_queue(), ^{ 25 | 26 | float time = 0; 27 | if(duration == 0){ 28 | time = 2; 29 | } 30 | else if(duration == 1){ 31 | time = 3.5; 32 | } 33 | else{ 34 | return; 35 | } 36 | 37 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil 38 | message:message 39 | preferredStyle:UIAlertControllerStyleAlert]; 40 | 41 | UIViewController *top = [[UIApplication sharedApplication] delegate].window.rootViewController; 42 | [top presentViewController:alert animated:YES completion: nil]; 43 | 44 | dispatch_after( 45 | dispatch_time(DISPATCH_TIME_NOW, time * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 46 | [alert dismissViewControllerAnimated:YES completion:nil]; 47 | } 48 | ); 49 | 50 | }); 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/Utils/ObjC_Convert.cpp: -------------------------------------------------------------------------------- 1 | #include "ObjC_Convert.h" 2 | 3 | //-- ObjC Convert 4 | 5 | // NSString to FString 6 | FString ObjCconvert::ToFString(NSString* String) 7 | { 8 | std::string TmpStr = std::string([String UTF8String]); 9 | return TmpStr.c_str(); 10 | } 11 | 12 | // NSString to std::string 13 | string ObjCconvert::ToString(NSString* String) 14 | { 15 | return std::string([String UTF8String]); 16 | } 17 | 18 | // NSMutableDictionary* to TArray 19 | TArray ObjCconvert::NSMutableArrayToTArrayFString (NSMutableArray* mArray) 20 | { 21 | TArray TmpArr; 22 | for (NSString* item in mArray) { 23 | TmpArr.Add( ObjCconvert::ToFString(item) ); 24 | } 25 | return TmpArr; 26 | } 27 | 28 | // NSMutableDictionary* to TArray 29 | TArray ObjCconvert::NSMutableArrayToTArrayInt(NSMutableArray* mArray) 30 | { 31 | TArray TmpArr; 32 | for (NSNumber* item in mArray) { 33 | TmpArr.Add([item intValue]); 34 | } 35 | return TmpArr; 36 | } 37 | 38 | // NSMutableDictionary* to TArray 39 | TArray ObjCconvert::NSMutableArrayToTArrayFloat(NSMutableArray* mArray) 40 | { 41 | TArray TmpArr; 42 | for (NSNumber* item in mArray) { 43 | TmpArr.Add([item floatValue]); 44 | } 45 | return TmpArr; 46 | } 47 | 48 | // TArray to NSMutableDictionary* 49 | NSMutableArray* ObjCconvert::TArrayFStringToNSMutableArray(TArray mArray) 50 | { 51 | NSMutableArray* mMutableArray = [NSMutableArray array]; 52 | for (auto item : mArray) { 53 | [mMutableArray addObject: item.GetNSString() ]; 54 | } 55 | return mMutableArray; 56 | } 57 | 58 | // TArray to NSMutableDictionary* 59 | template 60 | NSMutableArray* ObjCconvert::TArrayNumToNSMutableArray(TArray mArray) 61 | { 62 | NSMutableArray* mMutableArray = [NSMutableArray array]; 63 | for (auto item : mArray) { 64 | NSNumber* num = [NSNumber numberWithFloat : (anyType)item]; 65 | [mMutableArray addObject:num] ; 66 | } 67 | return mMutableArray; 68 | } -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/IOS/Utils/ObjC_Convert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | //creating an alias "let" for the autotype constant 9 | #define let __auto_type const 10 | //creating an alias " var " for the autotype 11 | #define var __auto_type 12 | 13 | class ObjCconvert 14 | { 15 | //======= Functions for converting to ObjC types ================ 16 | public: 17 | // NSString to FString 18 | static FString ToFString(NSString* String); 19 | 20 | // NSString to std::string 21 | static string ToString(NSString* String); 22 | 23 | // NSMutableDictionary* to TArray 24 | static TArray NSMutableArrayToTArrayFString(NSMutableArray* mArray); 25 | 26 | // NSMutableDictionary* to TArray 27 | static TArray NSMutableArrayToTArrayInt(NSMutableArray* mArray); 28 | 29 | // NSMutableDictionary* to TArray 30 | static TArray NSMutableArrayToTArrayFloat(NSMutableArray* mArray); 31 | 32 | // TArray to NSMutableDictionary* 33 | static NSMutableArray* TArrayFStringToNSMutableArray(TArray mArray); 34 | 35 | // TArray to NSMutableDictionary* 36 | template 37 | static NSMutableArray* TArrayNumToNSMutableArray(TArray mArray); 38 | }; 39 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/MobileNativeCode.cpp: -------------------------------------------------------------------------------- 1 | #include "MobileNativeCode.h" 2 | #include "MobileNativeCodeEditorSettings.h" 3 | 4 | #if PLATFORM_ANDROID 5 | #include "Android/Utils/AndroidUtils.h" 6 | #endif 7 | 8 | #define LOCTEXT_NAMESPACE "FMobileNativeCodeModule" 9 | 10 | /** 11 | * This code will be executed after loading your module into memory; 12 | * the exact time is specified in the .plugin file for each module. 13 | */ 14 | void FMobileNativeCodeModule::StartupModule() 15 | { 16 | // Register settings: `Settings -> Project Settings -> Plugins -> MobileNativeCode` 17 | if (ISettingsModule* settingsModule = FModuleManager::GetModulePtr("Settings")) 18 | { 19 | UMobileNativeCodeEditorSettings::RegisterEditorSettings(settingsModule); 20 | } 21 | 22 | // Initialization for Mobile Device 23 | Initialization(); 24 | } 25 | 26 | /** 27 | * This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 28 | * we call this function before unloading the module. 29 | */ 30 | void FMobileNativeCodeModule::ShutdownModule() 31 | { 32 | 33 | 34 | 35 | } 36 | 37 | void FMobileNativeCodeModule::Initialization() 38 | { 39 | #if PLATFORM_ANDROID 40 | AndroidUtils::Initialization(); 41 | #endif 42 | 43 | 44 | #if PLATFORM_IOS 45 | 46 | #endif 47 | } 48 | 49 | bool FMobileNativeCodeModule::IsSupported() 50 | { 51 | #if PLATFORM_ANDROID 52 | return AndroidUtils::isSupportPlatform(); 53 | #endif 54 | 55 | 56 | #if PLATFORM_IOS 57 | return true; 58 | #endif 59 | 60 | return false; 61 | } 62 | 63 | 64 | #undef LOCTEXT_NAMESPACE 65 | 66 | IMPLEMENT_MODULE(FMobileNativeCodeModule, MobileNativeCode) -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/MobileNativeCodeBlueprint.cpp: -------------------------------------------------------------------------------- 1 | #include "MobileNativeCodeBlueprint.h" 2 | 3 | #include "MobileNativeCode.h" 4 | #include 5 | #include 6 | 7 | // All Java classes are on the path: "MobileNativeCode\Source\MobileNativeCode\Private\Android\Java\" 8 | // All Objective-C classes are on the path: "MobileNativeCode\Source\MobileNativeCode\Private\IOS\ObjC\" 9 | 10 | #if PLATFORM_ANDROID 11 | #include "Android/Utils/AndroidUtils.h" 12 | #endif 13 | 14 | #if PLATFORM_IOS 15 | #include "IOS/Utils/ObjC_Convert.h" 16 | 17 | #include "IOS/ObjC/IosHelloWorld.h" 18 | #include "IOS/ObjC/IosAsyncHelloWorld.h" 19 | #include "IOS/ObjC/IosNativeUI.h" 20 | #include "IOS/ObjC/IosExampleArray.h" 21 | #include "IOS/ObjC/IosDeviceInfo.h" 22 | #endif 23 | 24 | 25 | 26 | // #~~~~~~~~~~~~~~~~~~~~~~~~~~~ begin 1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 27 | FString UMobileNativeCodeBlueprint::HelloWorld(FString MyStr /*= "Hello World"*/) 28 | { 29 | #if PLATFORM_ANDROID 30 | 31 | MyStr = AndroidUtils::CallJavaCode( 32 | "com/Plugins/MobileNativeCode/HelloWorldClass", // package (used by com/Plugins/MobileNativeCode) and the name of your Java class. 33 | "HelloWorldOnAndroid", //Name of your Java function. 34 | "", //Set your own signature instead of an automatic one (Send an empty one if you need an automatic one). 35 | false, //Determines whether to pass Activity UE4 to Java. 36 | MyStr //A list of your parameters in the Java function. 37 | ); 38 | 39 | #endif //Android 40 | 41 | 42 | #if PLATFORM_IOS 43 | 44 | //The Objective-C language can be mixed with C++ in a single file 45 | MyStr = FString([IosHelloWorld HelloWorldOnIOS : MyStr.GetNSString()]); 46 | 47 | #endif// IOS 48 | 49 | return MyStr; 50 | } 51 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ end 1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 52 | 53 | 54 | 55 | // #~~~~~~~~~~~~~~~~~~~~~~~~~~~ begin 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 56 | //-- Initialization of static variables 57 | FTypeDispacth UMobileNativeCodeBlueprint::StaticValueDispatch; 58 | 59 | 60 | void UMobileNativeCodeBlueprint::asyncHelloWorld(const FTypeDispacth& CallBackPlatform, FString MyStr /*= "async Hello World"*/) 61 | { 62 | UMobileNativeCodeBlueprint::StaticValueDispatch = CallBackPlatform; 63 | 64 | #if PLATFORM_ANDROID 65 | 66 | AndroidUtils::CallJavaCode( 67 | "com/Plugins/MobileNativeCode/asyncHelloWorldClass", 68 | "asyncHelloWorldOnAndroid", 69 | "", 70 | true, 71 | MyStr 72 | ); 73 | 74 | #endif //Android 75 | 76 | 77 | #if PLATFORM_IOS 78 | 79 | [IosAsyncHelloWorld asyncHelloWorldOnIOS : MyStr.GetNSString()]; 80 | 81 | #endif // IOS 82 | } 83 | 84 | void UMobileNativeCodeBlueprint::StaticFunctDispatch(const FString& ReturnValue) 85 | { 86 | //Lambda function for the dispatcher 87 | AsyncTask(ENamedThreads::GameThread, [ReturnValue]() { 88 | StaticValueDispatch.ExecuteIfBound(ReturnValue); 89 | }); 90 | } 91 | 92 | //-- Functions CallBack for Java code 93 | #if PLATFORM_ANDROID 94 | JNI_METHOD void Java_com_Plugins_MobileNativeCode_asyncHelloWorldClass_CallBackCppAndroid(JNIEnv* env, jclass clazz, jstring returnStr) 95 | { 96 | FString result = JavaConvert::FromJavaFString(returnStr); 97 | UE_LOG(LogTemp, Warning, TEXT("asyncHelloWorld callback caught in C++! - [%s]"), *FString(result)); //Debug log for UE4 98 | UMobileNativeCodeBlueprint::StaticFunctDispatch(result);// Call Dispatcher 99 | } 100 | #endif //PLATFORM_ANDROID 101 | 102 | //-- Functions CallBack for iOS code 103 | #if PLATFORM_IOS 104 | void UMobileNativeCodeBlueprint::CallBackCppIOS(NSString* sResult) 105 | { 106 | FString fResult = FString(sResult); 107 | UE_LOG(LogTemp, Warning, TEXT("asyncHelloWorld callback caught in C++! - [%s]"), *FString(fResult)); //Debug log for UE4 108 | UMobileNativeCodeBlueprint::StaticFunctDispatch(fResult); // Call Dispatcher 109 | } 110 | #endif //PLATFORM_IOS 111 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~ end 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 112 | 113 | 114 | 115 | // #~~~~~~~~~~~~~~~~~~~~~~~~~~~ begin 3 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 116 | void UMobileNativeCodeBlueprint::ShowToastMobile(FString Message, EToastLengthMessage Length) 117 | { 118 | #if PLATFORM_ANDROID 119 | 120 | AndroidUtils::CallJavaCode("com/Plugins/MobileNativeCode/NativeUI", "showToast", "", true, Message, (int)Length); 121 | 122 | #endif //Android 123 | 124 | #if PLATFORM_IOS 125 | 126 | // Calling a function using the singleton pattern 127 | [[IosNativeUI Singleton] showToast:Message.GetNSString() Duration:(int)Length]; 128 | 129 | #endif // IOS 130 | } 131 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ end 3 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 132 | 133 | 134 | 135 | // #~~~~~~~~~~~~~~~~~~~~~~~~~~~ begin 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 136 | void UMobileNativeCodeBlueprint::ExampleArray(FString& Arr1, FString& Arr2) 137 | { 138 | //Working with an array is done via TArray 139 | 140 | //Support argType = FString, bool, int, long, float, const char*, std::string 141 | TArray a1; 142 | TArray a2; 143 | TArray a3; 144 | TArray a4; 145 | TArray a5; 146 | 147 | //Support returnType = FString, int, float, long 148 | TArray TestStrArr; 149 | 150 | #if PLATFORM_ANDROID 151 | 152 | TestStrArr = AndroidUtils::CallJavaCode>( 153 | "com/Plugins/MobileNativeCode/ExampleArrayClass", // package (used by com/Plugins/MobileNativeCode) and the name of your Java class. 154 | "TestArray", // Name of your Java function. 155 | "", // Set your own signature instead of an automatic one (Send an empty one if you need an automatic one). 156 | false, // Determines whether to pass Activity UE4 to Java. 157 | a1, a2, a3, a4, a5 //A list of your parameters in the Java function. 158 | ); 159 | 160 | #endif //Android 161 | 162 | 163 | #if PLATFORM_IOS 164 | 165 | //The Objective-C language can be mixed with C++ in a single file 166 | TestStrArr = ObjCconvert::NSMutableArrayToTArrayFString([IosExampleArray 167 | TestArray : ObjCconvert::TArrayFStringToNSMutableArray(a1) 168 | b : ObjCconvert::TArrayNumToNSMutableArray(a2) 169 | i : ObjCconvert::TArrayNumToNSMutableArray(a3) 170 | f : ObjCconvert::TArrayNumToNSMutableArray(a4) 171 | l : ObjCconvert::TArrayNumToNSMutableArray(a5) 172 | ]); 173 | 174 | #endif // iOS 175 | 176 | Arr1 = TestStrArr[0]; 177 | Arr2 = TestStrArr[1]; 178 | } 179 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ end 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 180 | 181 | 182 | 183 | // #~~~~~~~~~~~~~~~~~~~~~~~~~~~ begin 5 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 184 | FString UMobileNativeCodeBlueprint::GetDeviceInfo() 185 | { 186 | FString sDeviceInfo; 187 | 188 | #if PLATFORM_ANDROID 189 | 190 | sDeviceInfo += " Your phone: "; 191 | sDeviceInfo += AndroidUtils::CallJavaCode("com/Plugins/MobileNativeCode/DeviceInfo", "getBrand", "", false); 192 | sDeviceInfo += " " + AndroidUtils::CallJavaCode("com/Plugins/MobileNativeCode/DeviceInfo", "getModel", "", false); 193 | 194 | sDeviceInfo += " Path to save files: "; 195 | // "storage/emulated/0/Android/data/data/%PROJECT_NAME%/" 196 | sDeviceInfo += AndroidUtils::CallJavaCode("com/Plugins/MobileNativeCode/DeviceInfo", "GetExternalFilesDir", "", true); 197 | 198 | #endif //Android 199 | 200 | 201 | #if PLATFORM_IOS 202 | 203 | sDeviceInfo += " Your phone: "; 204 | sDeviceInfo += FString([IosDeviceInfo getModel]); 205 | 206 | sDeviceInfo += " Path to save files: "; 207 | // "/var/mobile/Containers/Data/Application/%PROJECT_ID%/Library/Caches/" 208 | sDeviceInfo += FString([IosDeviceInfo getTmpFilePath]); 209 | 210 | #endif //PLATFORM_IOS 211 | 212 | return sDeviceInfo; 213 | } 214 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ end 5 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 215 | 216 | 217 | void UMobileNativeCodeBlueprint::ExampleMyJavaObject(FString& JavaBundle) 218 | { 219 | #if PLATFORM_ANDROID 220 | 221 | // Creating an empty jobject object, assigning it the standard java Bundle class 222 | // Bundle: https://developer.android.com/reference/android/os/Bundle 223 | 224 | //In order to populate a jobject with a Java class, you need to return it from your static Java function. 225 | 226 | jobject myJavaObject = AndroidUtils::CallJavaCode( 227 | "com/Plugins/MobileNativeCode/MyJavaObjects", // package (used by com/Plugins/MobileNativeCode) and the name of your Java class. 228 | "getBundleJava", // Name of your Java function. 229 | "()Landroid/os/Bundle;", // Set your own signature instead of an automatic one (Send an empty one if you need an automatic one). 230 | false // Determines whether to pass Activity UE4 to Java. 231 | ); 232 | 233 | // Functions such as putString and putDouble are defined inside Bunde. Let's call them with our parameters: 234 | 235 | AndroidUtils::CallJavaCode( 236 | myJavaObject, // the type of jobject from which you want to call a local Java function 237 | "putFloat", // Name of Java function. 238 | "", // Set your own signature instead of an automatic one (Send an empty one if you need an automatic one). 239 | "myKey", 1234.f // A list of your parameters in the Java function. 240 | ); 241 | 242 | AndroidUtils::CallJavaCode( 243 | myJavaObject, 244 | "putString", 245 | "", 246 | "myKey2", "myValueForBundle" 247 | ); 248 | 249 | 250 | // Let's see what's inside our Bundle 251 | JavaBundle = AndroidUtils::CallJavaCode( 252 | myJavaObject, // the type of jobject from which you want to call a local Java function 253 | "toString", // Name of Java function. 254 | "" // Set your own signature instead of an automatic one (Send an empty one if you need an automatic one). 255 | ); 256 | 257 | // After you have finished working with your jobject, you need to delete it 258 | AndroidUtils::DeleteJavaObject(myJavaObject); 259 | 260 | #endif //Android 261 | } 262 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Private/MobileNativeCodeEditorSettings.cpp: -------------------------------------------------------------------------------- 1 | #include "MobileNativeCodeEditorSettings.h" 2 | 3 | #define LOCTEXT_NAMESPACE "FMobileNativeCodeModule" 4 | 5 | UMobileNativeCodeEditorSettings::UMobileNativeCodeEditorSettings(const FObjectInitializer& ObjectInitializer) 6 | : Super(ObjectInitializer) 7 | { 8 | } 9 | 10 | //---------------------------------------------------------------------- 11 | void UMobileNativeCodeEditorSettings::RegisterEditorSettings(ISettingsModule* settingsModule) 12 | { 13 | settingsModule->RegisterSettings("Project", "Plugins", "MobileNativeCode", 14 | LOCTEXT("RuntimeSettingsName", "MobileNativeCode"), 15 | LOCTEXT("RuntimeSettingsDescription", "Configure bundle(plugin)"), 16 | GetMutableDefault()); 17 | } 18 | 19 | #undef LOCTEXT_NAMESPACE -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Public/MobileNativeCode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Modules/ModuleManager.h" 4 | 5 | class FMobileNativeCodeModule : public IModuleInterface 6 | { 7 | public: 8 | 9 | /** IModuleInterface implementation */ 10 | virtual void StartupModule() override; 11 | virtual void ShutdownModule() override; 12 | 13 | /** 14 | * Init 15 | */ 16 | void Initialization(); 17 | 18 | /** 19 | * Can the mobile platform call functions 20 | */ 21 | static bool IsSupported(); 22 | }; 23 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Public/MobileNativeCodeBlueprint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "NativeUI/Enums/ToastLengthMessage.h" 9 | 10 | #include "MobileNativeCodeBlueprint.generated.h" 11 | 12 | 13 | 14 | // #~~~~~~~~~~~~~~~~~~~~~~~~~ begin 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 | //-- Dispatcher 16 | DECLARE_DYNAMIC_DELEGATE_OneParam(FTypeDispacth, const FString&, ReturnValue); // DispatchName, ParamType, ParamName 17 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~ end 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 | 19 | 20 | UCLASS() 21 | class MOBILENATIVECODE_API UMobileNativeCodeBlueprint : public UBlueprintFunctionLibrary 22 | { 23 | GENERATED_BODY() 24 | public: 25 | UMobileNativeCodeBlueprint(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {}; 26 | 27 | // #~~~~~~~~~~~~~~~~~~~~~~~~ begin 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 28 | //-- Dispatcher 29 | 30 | static FTypeDispacth StaticValueDispatch; 31 | static void StaticFunctDispatch(const FString& ReturnValue); 32 | 33 | #if PLATFORM_IOS 34 | static void CallBackCppIOS(NSString* sResult); 35 | #endif //PLATFORM_IOS 36 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~ end 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | 38 | 39 | /** 40 | * Concatenation of the platform name from native code 41 | */ 42 | UFUNCTION(BlueprintCallable, Category = "MobileNativeCode Category") 43 | static FString HelloWorld(FString MyStr = "Hello World"); 44 | 45 | /** 46 | * Asynchronous platform name concatenation from native code 47 | */ 48 | UFUNCTION(BlueprintCallable, Category = "MobileNativeCode Category") 49 | static void asyncHelloWorld(const FTypeDispacth& CallBackPlatform, FString MyStr = "async Hello World"); 50 | 51 | /** 52 | * Displaying a pop-up message 53 | */ 54 | UFUNCTION(BlueprintCallable, Category = "MobileNativeCode Category") 55 | static void ShowToastMobile(FString Message, EToastLengthMessage Length); 56 | 57 | /** 58 | * Example of passing different types of arrays and returning a String array with two values 59 | */ 60 | UFUNCTION(BlueprintCallable, Category = "MobileNativeCode Category") 61 | static void ExampleArray(FString& Arr1, FString& Arr2); 62 | 63 | /** 64 | * Returns information about the device 65 | */ 66 | UFUNCTION(BlueprintCallable, Category = "MobileNativeCode Category") 67 | static FString GetDeviceInfo(); 68 | 69 | /** 70 | * Only for Android. Example of working with Java objects inside C++ 71 | */ 72 | UFUNCTION(BlueprintCallable, Category = "MobileNativeCode Category") 73 | static void ExampleMyJavaObject(FString& JavaBundle); 74 | }; 75 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Public/MobileNativeCodeEditorSettings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Developer/Settings/Public/ISettingsModule.h" 4 | #include "MobileNativeCodeEditorSettings.generated.h" 5 | 6 | UCLASS(config = Engine, defaultconfig) 7 | class UMobileNativeCodeEditorSettings : public UObject 8 | { 9 | GENERATED_BODY() 10 | 11 | public: 12 | UMobileNativeCodeEditorSettings(const FObjectInitializer& ObjectInitializer); 13 | 14 | static void RegisterEditorSettings(ISettingsModule* settingsModule); 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/Public/NativeUI/Enums/ToastLengthMessage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ToastLengthMessage.generated.h" 4 | 5 | UENUM(BlueprintType) 6 | enum class EToastLengthMessage : uint8 7 | { 8 | /** Short message duration 2 sec */ 9 | sec2 = 0 UMETA(DisplayName = "Short 2 sec"), 10 | 11 | /** Short message duration 3.5 sec */ 12 | sec3 = 1 UMETA(DisplayName = "Long 3.5 sec"), 13 | }; 14 | -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/ThirdParty/Android/arm64-v8a/lib/libc++_shared.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/MobileNativeCode/Source/MobileNativeCode/ThirdParty/Android/arm64-v8a/lib/libc++_shared.so -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/ThirdParty/Android/armeabi-v7a/lib/libc++_shared.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/MobileNativeCode/Source/MobileNativeCode/ThirdParty/Android/armeabi-v7a/lib/libc++_shared.so -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/ThirdParty/IOS/bundle/IosDrawable.bundle/my_test_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/MobileNativeCode/Source/MobileNativeCode/ThirdParty/IOS/bundle/IosDrawable.bundle/my_test_icon.png -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/ThirdParty/IOS/frameworks/GoogleMobileAdsMediationTestSuite.embeddedframework.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/MobileNativeCode/Source/MobileNativeCode/ThirdParty/IOS/frameworks/GoogleMobileAdsMediationTestSuite.embeddedframework.zip -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/ThirdParty/IOS/frameworks/PersonalizedAdConsent.embeddedframework.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/MobileNativeCode/Source/MobileNativeCode/ThirdParty/IOS/frameworks/PersonalizedAdConsent.embeddedframework.zip -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/ThirdParty/Windows/include/.h or .cpp file .txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/MobileNativeCode/Source/MobileNativeCode/ThirdParty/Windows/include/.h or .cpp file .txt -------------------------------------------------------------------------------- /MobileNativeCode/Source/MobileNativeCode/ThirdParty/Windows/lib/.dll or . lib file .txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/MobileNativeCode/Source/MobileNativeCode/ThirdParty/Windows/lib/.dll or . lib file .txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![Logo](screenshot/Logo3.png) 3 | 4 | # Mobile Native Code Plugin for Unreal Engine 4/5 5 | Plugin providing native mobile functionality access for Unreal Engine projects. Suitable for cases when you need: 6 | * Access to device-specific features and file system 7 | * Sensor data (Accelerometer, Barometer, etc.) 8 | * Device information 9 | * Inter-app communication 10 | * Integration with mobile services (Facebook, Firebase, Admob) 11 | 12 | **Mobile Native Code Plugin** serves as a foundation for native mobile development in Unreal Engine, supporting both Android and iOS platforms. It simplifies native code calls (Java/JNI and Objective-C) and provides examples of integrating external libraries. 13 | 14 | 15 | # Features 16 | ![Java](screenshot/CallJava4.png) 17 | 18 | * Engine Support: UE 4.21+ and UE 5.0+ 19 | * Used in commercial projects (UE 4.25-5.4) 20 | * Calling native Java code with a single function from C++ 21 | * Examples of functions for interacting with native code 22 | 23 | Source locations: 24 | > **Blueprint/C++**: MobileNativeCode/Source/MobileNativeCode/Private/MobileNativeCodeBlueprint.cpp 25 | 26 | > **Android**: MobileNativeCode/Source/MobileNativeCode/Private/Android/Java/ 27 | 28 | > **iOS**: MobileNativeCode/Source/MobileNativeCode/Private/IOS/ObjC/ 29 | 30 | Requirements: 31 | * Visual Studio for Windows 32 | * Xcode for iOS 33 | 34 | # Setup 35 | 36 | 1) Copy MobileNativeCode to the Plugins folder located in the main path of your project (if not, create it). 37 | 38 | ![PathPlugin](screenshot/PathPlugin2.png) 39 | 40 | 2) Enable MobileNativeCode in Edit->Plugins->Installed->Mobile->MobileNativeCode. Restart the editor. 41 | 42 | ![EnablePlugin](screenshot/EnablePlugin1.png) 43 | 44 | 3) in the LevelBlueprint, create a diagram. 45 | 46 | ![LevelBlueprint](screenshot/LevelBlueprint2.png) 47 | 48 | 4) **Run on your mobile device.** 49 | 50 | 5) Go to *"MobileNativeCode\Source\MobileNativeCode\Private\MobileNativeCodeBlueprint.cpp"* to find out how these functions work 51 | 52 | # Testing 53 | 54 | **Android** 55 | 56 | ![HonorPlay](screenshot/HonorPlay_2.png) 57 | 58 | **iOS** 59 | 60 | ![iPhone7](screenshot/iPhone7_2.png) 61 | 62 | # Additional information 63 | 64 | ## for Android 65 | 66 | * Go to *MobileNativeCode\Source\MobileNativeCode\Private* and open *MobileNativeCodeBlueprint.cpp*. 67 | This file demonstrates 5 functions for calling Java code. 68 | 69 | * **(IMPORTANT!)** When adding a new Java class or changing the current one, delete the **Intermediate** folder in your project folder. 70 | 71 | * **Note for UE4 users**: If you're using UE4, uncomment the following code block in `MobileNativeCode_UPL_Android.xml`: 72 | ```xml 73 | 74 | 83 | ``` 84 | 85 | To call your own Java class: 86 | 87 | * Add your *Java* class to the folder: *MobileNativeCode\Source\MobileNativeCode\Private\Android\Java* 88 | 89 | * Change the value of *package* at: **com.Plugins.MobileNativeCode** 90 | 91 | * before the class and functions, add ***@Keep*** 92 | 93 | * Java code is called using **AndroidUtils::CallJavaCode...** 94 | This function has two overloads for **static** and **local** Java functions: 95 | 96 | > **AndroidUtils::CallJavaCode< *ReturnType* >("com/Plugins/MobileNativeCode/*YourClass*", "*YourFunction*", "", false, arg1, arg2, arg3)** 97 | >* *ReturnType* - is specified depending on the return type. For example *FString* or *TArray< float >* 98 | >* *1 argument* - is package+the name of your class 99 | >* *2 argument* - the name of your function 100 | >* *3 argument* - Set your own signature instead of an automatic one (send a blank one if you need an automatic one). 101 | > In most cases, this argument will be empty 102 | >* *4 argument* - indicates whether to pass the *Java main Activity* of this session. 103 | > If you want to pass an Activity, it should be specified first in the list of arguments of your Java function 104 | >* Further, the number of arguments can be passed as many as you want, depending on what your function accepts. 105 | 106 | > **AndroidUtils::CallJavaCode< *ReturnType* >(*JavaObjectClass*, "*YourFunction*", "", arg1, arg2, arg3)** 107 | >* *ReturnType* - is specified depending on the return type. For example *FString* or *TArray< float >* 108 | >* *1 argument* - the type of *jobject* that you want to call the local function from 109 | >* *2 argument* - the name of your function 110 | >* *3 argument* - Set your own signature instead of an automatic one (send a blank one if you need an automatic one). 111 | > For example, if the function does not accept any parameters and returns the type of the Bundle class, you should specify **"()Landroid/os/Bundle;"** 112 | >* Further, the number of arguments can be passed as many as you want, depending on what your function accepts. 113 | 114 | * OverrideSignature is specified so that JNI can find the desired function among all java files. Most of the standard types have been added to the plugin and therefore the 3rd function argument can be left empty. For some complex types (for example Bundle) you need to install it. 115 | 116 | * To define *Signature* for complex types, you need to add your class to *"MobileNativeCode\Source\MobileNativeCode\ Private\Android\Java\"* and build your Android project. After a successful build, in your project folder navigate to: *"Intermediate\Android\ % ARCH% \gradle\app\build\intermediates\javac\debug\classes\com\Plugins\MobileNativeCode"* 117 | you will see files with ***.class** type. You need to add the path of your **jdk/bin** to the system variables in **PATH**, then you need to open *PowerShell* or *Cmd* in this folder and enter the command **"javap -s YourJavaClass"**. After that, a list of all your functions will appear, our *Signature* will be in the descriptor field. 118 | ![SignatureJava](screenshot/Javap_Android.png) 119 | 120 | * The ***UMobileNativeCodeBlueprint::ExampleMyJavaObject*** function shows an example of working with local Java objects. In order to assign any Java class to your jobject, you need to return it from a static variable (for example, *return new Bundle ();*) and then call the functions of this jobject, as in Java: 121 | ![JavaBundle](screenshot/JavaBundle_Android.png) 122 | 123 | * Asynchronous Java invocation occurs through dispatchers UE4 - Java code calls a C++ function, which in turn activates it. 124 | 125 | ## For iOS 126 | 127 | * The Objective-C language can be written in **. cpp* files, but it is better to use **. mm* file 128 | 129 | * For some code, you need the key and the resolution (or another Description). The entire list can be seen at the links: 130 | [Description Apple](https://developer.apple.com/documentation/bundleresources/information_property_list/protected_resources), 131 | [Key Apple](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple_ref/doc/uid/TP40009252-SW3) 132 | 133 | * These permissions can be added in Unreal engine 4 itself in the IOS section, but I suggest using the file *MobileNativeCode_UPL_iOS.xml* by path *MobileNativeCode\Source\MobileNativeCode* 134 | In the commented lines, there is an example of how information is added to the Info.plist 135 | 136 | * You can see the list of connected public libraries in the file *MobileNativeCode\Source\MobileNativeCode\MobileNativeCode.Build.cs* 137 | ![build](screenshot/IOS_framework2.png) 138 | * If you don't have the Framework you need, add it yourself by simply continuing the list. 139 | [Learn more about the IOS Framework](https://developer.apple.com/documentation/technologies) 140 | 141 | * Also **MobileNativeCode.Build.cs** shows examples of connecting libraries **.framework and* **.bundle* in **.ipa* file 142 | 143 | To call Objective-C code 144 | 145 | * Add your *Objective-C* class to the *MobileNativeCode\Source\MobileNativeCode\Private\IOS\ObjC* folder 146 | 147 | * Connect it to *MobileNativeCode\Source\MobileNativeCode\Private\MobileNativeCodeBlueprint.cpp* 148 | -------------------------------------------------------------------------------- /screenshot/CallJava4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/screenshot/CallJava4.png -------------------------------------------------------------------------------- /screenshot/EnablePlugin1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/screenshot/EnablePlugin1.png -------------------------------------------------------------------------------- /screenshot/HonorPlay_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/screenshot/HonorPlay_2.png -------------------------------------------------------------------------------- /screenshot/IOS_framework2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/screenshot/IOS_framework2.png -------------------------------------------------------------------------------- /screenshot/JavaBundle_Android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/screenshot/JavaBundle_Android.png -------------------------------------------------------------------------------- /screenshot/Javap_Android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/screenshot/Javap_Android.png -------------------------------------------------------------------------------- /screenshot/LevelBlueprint2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/screenshot/LevelBlueprint2.png -------------------------------------------------------------------------------- /screenshot/Logo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/screenshot/Logo3.png -------------------------------------------------------------------------------- /screenshot/PathPlugin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/screenshot/PathPlugin2.png -------------------------------------------------------------------------------- /screenshot/iPhone7_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sovahero/PluginMobileNativeCode/139a2cafb2db0339f5b37148a601acd67e9ffaf5/screenshot/iPhone7_2.png --------------------------------------------------------------------------------