├── 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 | 
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 | 
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 | 
39 |
40 | 2) Enable MobileNativeCode in Edit->Plugins->Installed->Mobile->MobileNativeCode. Restart the editor.
41 |
42 | 
43 |
44 | 3) in the LevelBlueprint, create a diagram.
45 |
46 | 
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 | 
57 |
58 | **iOS**
59 |
60 | 
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 | 
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 | 
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 | 
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
--------------------------------------------------------------------------------