Commit 395ab83b by Minhan Jeong

Init Repository

parents
### UnrealEngine ###
# Visual Studio 2015 user specific files
.vs/
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
# Compiled Static libraries
*.lai
*.la
# *.a
# *.lib
# Executables
*.exe
*.out
*.app
*.ipa
# These project files can be generated by the engine
*.xcodeproj
*.xcworkspace
*.sln
*.suo
*.opensdf
*.sdf
*.VC.db
*.VC.opendb
# Jinkyu
Content/Private
# Precompiled Assets
SourceArt/**/*.png
SourceArt/**/*.tga
# Binary Files
Binaries/*
Plugins/*/Binaries/*
# Builds
Build/*
# Whitelist PakBlacklist-<BuildConfiguration>.txt files
!Build/*/
Build/*/**
!Build/*/PakBlacklist*.txt
# Don't ignore icon files in Build
!Build/**/*.ico
# Configuration files generated by the Editor
Saved/*
# Compiled source files for the engine to use
Intermediate/*
Plugins/*/Intermediate/*
# Cache files for the editor to use
DerivedDataCache/*
### UnrealEngine Patch ###
# Don't ignore icon and splash images for mobile app
!Build/IOS/Resources/
Build/IOS/Resources/*
!Build/IOS/Resources/Graphics/
Build/IOS/Resources/Graphics/*
!Build/IOS/Resources/Graphics/*.png
!Build/Android/res/
Build/Android/res/*
!Build/Android/res/*/
Build/Android/res/*/*
!Build/Android/res/*/*.png
### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.iobj
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.cachefile
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*[.json, .xml, .info]
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
Build/
# Rider for Unreal Engine
.idea
\ No newline at end of file
[/Script/HardwareTargeting.HardwareTargetingSettings]
TargetedHardwareClass=Mobile
AppliedTargetedHardwareClass=Mobile
DefaultGraphicsPerformance=Maximum
AppliedDefaultGraphicsPerformance=Maximum
[/Script/EngineSettings.GameMapsSettings]
EditorStartupMap=/Game/MobileStarterContent/Maps/HuaweiMap.HuaweiMap
LocalMapOptions=
TransitionMap=None
bUseSplitscreen=False
TwoPlayerSplitscreenLayout=Horizontal
ThreePlayerSplitscreenLayout=FavorTop
FourPlayerSplitscreenLayout=Grid
bOffsetPlayerGamepadIds=False
GameInstanceClass=/Script/Engine.GameInstance
GameDefaultMap=/Game/MobileStarterContent/Maps/HuaweiMap.HuaweiMap
ServerDefaultMap=/Engine/Maps/Entry.Entry
GlobalDefaultGameMode=/Script/Engine.GameModeBase
GlobalDefaultServerGameMode=None
[/Script/Engine.Engine]
+ActiveGameNameRedirects=(OldGameName="TP_Blank",NewGameName="/Script/Huawei")
+ActiveGameNameRedirects=(OldGameName="/Script/TP_Blank",NewGameName="/Script/Huawei")
+ActiveClassRedirects=(OldClassName="TP_BlankGameModeBase",NewClassName="HuaweiGameModeBase")
[/Script/Engine.RendererSettings]
r.Mobile.DisableVertexFog=True
r.Shadow.CSM.MaxMobileCascades=2
r.MobileMSAA=1
r.Mobile.UseLegacyShadingModel=False
r.Mobile.AllowDitheredLODTransition=False
r.Mobile.AllowSoftwareOcclusion=False
r.Mobile.VirtualTextures=False
r.DiscardUnusedQuality=False
r.AllowOcclusionQueries=True
r.MinScreenRadiusForLights=0.030000
r.MinScreenRadiusForDepthPrepass=0.030000
r.MinScreenRadiusForCSMDepth=0.010000
r.PrecomputedVisibilityWarning=False
r.TextureStreaming=True
Compat.UseDXT5NormalMaps=False
r.VirtualTextures=False
r.VirtualTexturedLightmaps=False
r.VT.TileSize=128
r.VT.TileBorderSize=4
r.vt.FeedbackFactor=16
r.VT.EnableCompressZlib=True
r.VT.EnableCompressCrunch=False
r.ClearCoatNormal=False
r.AnisotropicBRDF=False
r.ReflectionCaptureResolution=128
r.ReflectionEnvironmentLightmapMixBasedOnRoughness=True
r.ForwardShading=False
r.VertexFoggingForOpaque=True
r.AllowStaticLighting=True
r.NormalMapsForStaticLighting=False
r.GenerateMeshDistanceFields=False
r.DistanceFieldBuild.EightBit=False
r.GenerateLandscapeGIData=False
r.DistanceFieldBuild.Compress=False
r.TessellationAdaptivePixelsPerTriangle=48.000000
r.SeparateTranslucency=False
r.TranslucentSortPolicy=0
TranslucentSortAxis=(X=0.000000,Y=-1.000000,Z=0.000000)
r.CustomDepth=1
r.CustomDepthTemporalAAJitter=True
r.PostProcessing.PropagateAlpha=0
r.DefaultFeature.Bloom=True
r.DefaultFeature.AmbientOcclusion=False
r.DefaultFeature.AmbientOcclusionStaticFraction=True
r.DefaultFeature.AutoExposure=False
r.DefaultFeature.AutoExposure.Method=0
r.DefaultFeature.AutoExposure.Bias=1.000000
r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange=False
r.UsePreExposure=True
r.EyeAdaptation.EditorOnly=False
r.DefaultFeature.MotionBlur=False
r.DefaultFeature.LensFlare=False
r.TemporalAA.Upsampling=False
r.SSGI.Enable=False
r.DefaultFeature.AntiAliasing=0
r.DefaultFeature.LightUnits=1
r.DefaultBackBufferPixelFormat=4
r.Shadow.UnbuiltPreviewInGame=True
r.StencilForLODDither=False
r.EarlyZPass=3
r.EarlyZPassOnlyMaterialMasking=False
r.DBuffer=True
r.ClearSceneMethod=1
r.BasePassOutputsVelocity=False
r.VertexDeformationOutputsVelocity=False
r.SelectiveBasePassOutputs=False
bDefaultParticleCutouts=False
fx.GPUSimulationTextureSizeX=1024
fx.GPUSimulationTextureSizeY=1024
r.AllowGlobalClipPlane=False
r.GBufferFormat=1
r.MorphTarget.Mode=True
r.GPUCrashDebugging=False
vr.InstancedStereo=False
r.MobileHDR=True
vr.MobileMultiView=False
r.Mobile.UseHWsRGBEncoding=False
vr.RoundRobinOcclusion=False
vr.ODSCapture=False
r.MeshStreaming=False
r.WireframeCullThreshold=5.000000
r.RayTracing=False
r.RayTracing.UseTextureLod=False
r.SupportStationarySkylight=True
r.SupportLowQualityLightmaps=True
r.SupportPointLightWholeSceneShadows=True
r.SupportAtmosphericFog=True
r.SupportSkyAtmosphere=True
r.SupportSkyAtmosphereAffectsHeightFog=False
r.SkinCache.CompileShaders=False
r.SkinCache.DefaultBehavior=1
r.SkinCache.SceneMemoryLimitInMB=128.000000
r.Mobile.EnableStaticAndCSMShadowReceivers=True
r.Mobile.EnableMovableLightCSMShaderCulling=True
r.Mobile.AllowDistanceFieldShadows=True
r.Mobile.AllowMovableDirectionalLights=True
r.MobileNumDynamicPointLights=4
r.MobileDynamicPointLightsUseStaticBranch=True
r.Mobile.EnableMovableSpotlights=False
r.GPUSkin.Support16BitBoneIndex=False
r.GPUSkin.Limit2BoneInfluences=False
r.SupportDepthOnlyIndexBuffers=True
r.SupportReversedIndexBuffers=True
r.SupportMaterialLayers=False
r.LightPropagationVolume=False
[/Script/Slate.SlateSettings]
bExplicitCanvasChildZOrder=True
[/Script/AndroidRuntimeSettings.AndroidRuntimeSettings]
bDisableVerifyOBBOnStartUp=False
bPackageDataInsideApk=True
PackageName=com.tdf.rmvw2021.huawei
KeyStore=Release_rmvw2021.keystore
KeyAlias=rmvw2021
KeyStorePassword=3df1q2w3e
KeyPassword=3df1q2w3e
ApplicationDisplayName=Real Madrid Virtual World
[/Script/EngineSettings.GeneralProjectSettings]
ProjectID=5B49CC9046C811C23CB5B8B3B4A27751
[StartupActions]
bAddPacks=True
InsertPack=(PackSource="MobileStarterContent.upack",PackName="StarterContent")
{
"FileVersion": 3,
"EngineAssociation": "4.25",
"Category": "",
"Description": "",
"Modules": [
{
"Name": "Huawei",
"Type": "Runtime",
"LoadingPhase": "Default"
}
],
"Plugins": [
{
"Name": "MobileNativeCode",
"Enabled": false
}
]
}
\ No newline at end of file
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "HuaweiSDK",
"Description": "",
"Category": "Other",
"CreatedBy": "",
"CreatedByURL": "",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "",
"CanContainContent": true,
"IsBetaVersion": false,
"IsExperimentalVersion": false,
"Installed": false,
"Modules": [
{
"Name": "HuaweiSDK",
"Type": "Runtime",
"LoadingPhase": "Default"
}
]
}
\ No newline at end of file
// Copyright Epic Games, Inc. All Rights Reserved.
using System.IO;
using UnrealBuildTool;
public class HuaweiSDK : ModuleRules
{
//=======Path===================================================================
private string ThirdPartyPath
{
get { return Path.GetFullPath(Path.Combine(ModuleDirectory, "ThirdParty/")); }
}
private string PathThirdPartyAndroid
{
get { return Path.GetFullPath(Path.Combine(ThirdPartyPath, "Android/")); }
}
public HuaweiSDK(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
if (Target.Platform == UnrealTargetPlatform.Android)
{
string ArchArmV7a = "armeabi-v7a";
string ArchArmV8a = "arm64-v8a";
PublicDependencyModuleNames.AddRange(new string[] { "Launch" });
PrivateIncludePaths.AddRange(new []{ Path.Combine(ModuleDirectory, "Private", "Android") });
// libc++_shared.so already added, but if you use the engine version 4.24 or less, you can uncomment these lines and in xml
string[] Libs = {
//"libc++_shared.so",
};
foreach (string Lib in Libs)
{
PublicAdditionalLibraries.Add(Path.Combine(PathThirdPartyAndroid, ArchArmV7a, "lib", Lib));
PublicAdditionalLibraries.Add(Path.Combine(PathThirdPartyAndroid, ArchArmV8a, "lib", Lib));
}
string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, Target.RelativeEnginePath);
AdditionalPropertiesForReceipt.Add("AndroidPlugin", Path.Combine(PluginPath, "HuaweiSDK_UPL.xml"));
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- HuaweiSDk Plugin addtions-->
<root xmlns:android="http://schemas.android.com/apk/res/android">
<init>
<log text="Loading HuaweiSDK_UPL.xml"/>
<setStringFromProperty result="PackageName" ini="Engine" section="/Script/AndroidRuntimeSettings.AndroidRuntimeSettings" property="PackageName" default=""/>
</init>
<androidManifestUpdates>
<addElement tag="application">
<meta-data android:name="com.huawei.hms.client.channel.androidMarket" android:value="true"/>
</addElement>
</androidManifestUpdates>
<gradleCopies>
<log text="Copyin EasyFirebase files to staging"/>
<copyFile src="$S(PluginDir)/agconnect-services.json"
dst="$S(BuildDir)/gradle/app/agconnect-services.json"/>
</gradleCopies>
<prebuildCopies>
<copyDir src="$S(PluginDir)/Private/Android/Java"
dst="$S(BuildDir)/src/com/Plugins/HuaweiSDK"/>
</prebuildCopies>
<!-- Android -->
<resourceCopies>
<log text="Copying Java files to staging"/>
<!-- <copyDir src="$S(PluginDir)/Java" dst="$S(BuildDir)/src"/>-->
<!-- <isArch arch="armeabi=v7a"></isArch>-->
<!-- <isArch arch="arm64-v8a"></isArch>-->
</resourceCopies>
<proguardAdditions>
<insert>
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
-dontwarn com.Plugins.**
-keep class com.Plugins.** { *; }
-keep interface com.Plugins.** { *; }
-keep public class com.Plugins.HuaweiSDK.** { public protected *; }
</insert>
</proguardAdditions>
<!-- <androidManifestUpdates>-->
<!-- <setElement result="HuaweiSDKActivity" value="activity"/>-->
<!-- <addAttribute tag="$HuaweiSDKActivity" name="android:name" value="com.hmsiap.huawei"/>-->
<!-- <addAttribute tag="$HuaweiSDKActivity" name="android:label" value="@string/app_name"/>-->
<!-- <addElement tag="application" name="HuaweiSDKActivity"/>-->
<!-- </androidManifestUpdates>-->
<buildscriptGradleAdditions>
<insert>
dependencies
{
repositories
{
google()
jcenter()
maven {url 'http://developer.huawei.com/repo/'}
}
classpath "com.android.tools.build:gradle:3.5.4"
classpath 'com.huawei.agconnect:agcp:1.4.2.301'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
</insert>
</buildscriptGradleAdditions>
<buildGradleAdditions>
<insert>
apply plugin: 'com.android.application'
dependencies
{
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.huawei.hms:iap:6.0.0.300'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
}
allprojects
{
repositories
{
google()
jcenter()
maven {url 'http://developer.huawei.com/repo/'}
}
}
apply plugin: 'com.huawei.agconnect'
</insert>
</buildGradleAdditions>
<gameActivityImportAdditions>
<insertValue value="import $S(PackageName).R;"/>
<insertNewline/>
<insert>
import android.os.Bundle;
import android.app.ActivityManager;
import com.Plugins.HuaweiSDK.activity.ConsumptionActivity;
import com.Plugins.HuaweiSDK.activity.EntryActivity;
</insert>
</gameActivityImportAdditions>
<gameActivityPostImportAdditions>
<insert>
</insert>
</gameActivityPostImportAdditions>
<gameActivityClassAdditions>
<insert>
private ConsumptionActivity mConsumptionActivity;
private EntryActivity mEntryActivity;
public void AndroidThunkJava_CreateHuaweiIap()
{
mConsumptionActivity = new ConsumptionActivity(this);
}
public void AndroidThunkJava_IsEnvReady()
{
mEntryActivity = new EntryActivity(this);
}
public void AndroidThunkJava_QueryProducts()
{
mEntryActivity.QueryProducts();
}
public void AndroidThunkJava_Payment(String productId)
{
mEntryActivity.Payment(productId);
}
</insert>
</gameActivityClassAdditions>
<gameActivityOnCreateAdditions>
<insert>
</insert>
</gameActivityOnCreateAdditions>
<gameActivityOnActivityResultAdditions>
<insert>
mEntryActivity.onActivityResult(requestCode, resultCode, data);
</insert>
</gameActivityOnActivityResultAdditions>
</root>
\ No newline at end of file
package com.Plugins.HuaweiSDK.activity;
import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.Plugins.HuaweiSDK.common.CipherUtil;
import com.Plugins.HuaweiSDK.common.Constants;
import com.Plugins.HuaweiSDK.common.ExceptionHandle;
import com.Plugins.HuaweiSDK.common.IapApiCallback;
import com.Plugins.HuaweiSDK.common.IapRequestHelper;
import com.Plugins.HuaweiSDK.common.DeliveryUtils;
import com.huawei.hms.iap.Iap;
import com.huawei.hms.iap.IapClient;
import com.huawei.hms.iap.entity.InAppPurchaseData;
import com.huawei.hms.iap.entity.OrderStatusCode;
import com.huawei.hms.iap.entity.OwnedPurchasesResult;
import com.huawei.hms.iap.entity.ProductInfo;
import com.huawei.hms.iap.entity.ProductInfoResult;
import com.huawei.hms.iap.entity.PurchaseIntentResult;
import com.huawei.hms.support.api.client.Status;
import com.epicgames.ue4.Logger;
import org.json.JSONException;
import java.util.ArrayList;
import java.util.List;
public class ConsumptionActivity extends Activity
{
private static final Logger Log = new Logger("UE4-" + ConsumptionActivity.class);
private String TAG = "ConsumptionActivity";
private List<ProductInfo> consumableProducts = new ArrayList<ProductInfo>();
private IapClient mClient;
private Activity mActivity;
public ConsumptionActivity(final Activity activity)
{
mActivity = activity;
Log.verbose(TAG + " Create Activity");
mClient = Iap.getIapClient(mActivity);
queryPurchases(null);
}
// @Override
// protected void onCreate(Bundle saveInstanceState)
// {
// Log.verbose(TAG + "onCreate");
//
// super.onCreate(saveInstanceState);
// mClient = Iap.getIapClient(this);
//
// queryPurchases(null);
// }
private void queryProducts()
{
List<String> productIds = new ArrayList<String>();
productIds.add("CProducts01");
IapRequestHelper.obtainProductInfo(mClient, productIds, IapClient.PriceType.IN_APP_CONSUMABLE, new IapApiCallback<ProductInfoResult>() {
@Override
public void onSuccess(ProductInfoResult result) {
Log.verbose(TAG + "obtainProductInfo, success");
if (result == null) {
return;
}
if (result.getProductInfoList() != null) {
consumableProducts = result.getProductInfoList();
}
// showProducts();
}
@Override
public void onFail(Exception e) {
Log.error(TAG + "obtainProductInfo: " + e.getMessage());
// ExceptionHandle.handle(ConsumptionActivity.this, e);
// showProducts();
}
});
}
/**
* Call the obtainOwnedPurchases API to obtain the data about consumable products that a user has purchased but has not been delivered.
*/
private void queryPurchases(String continuationToken) {
final String tag = "obtainOwnedPurchases";
Log.verbose(TAG + "Begin " + tag);
IapRequestHelper.obtainOwnedPurchases(mClient, IapClient.PriceType.IN_APP_CONSUMABLE, continuationToken, new IapApiCallback<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
if (result == null) {
Log.error(TAG + " " + tag + " result is null");
return;
}
Log.verbose(TAG + "obtainOwnedPurchases, success");
if (result.getInAppPurchaseDataList() != null) {
List<String> inAppPurchaseDataList = result.getInAppPurchaseDataList();
List<String> inAppSignature= result.getInAppSignature();
for (int i = 0; i < inAppPurchaseDataList.size(); i++) {
final String inAppPurchaseData = inAppPurchaseDataList.get(i);
final String inAppPurchaseDataSignature = inAppSignature.get(i);
deliverProduct(inAppPurchaseData, inAppPurchaseDataSignature);
}
}
if (!TextUtils.isEmpty(result.getContinuationToken())) {
queryPurchases(result.getContinuationToken());
}
}
@Override
public void onFail(Exception e) {
Log.error(TAG + "obtainOwnedPurchases, type=" + IapClient.PriceType.IN_APP_CONSUMABLE + ", " + e.getMessage());
// ExceptionHandle.handle(ConsumptionActivity.this, e);
}
});
}
private void deliverProduct(final String inAppPurchaseDataStr, final String inAppPurchaseDataSignature) {
if (CipherUtil.doCheck(inAppPurchaseDataStr, inAppPurchaseDataSignature, CipherUtil.getPublicKey())) {
try {
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseDataStr);
if (inAppPurchaseDataBean.getPurchaseState() != InAppPurchaseData.PurchaseState.PURCHASED) {
return;
}
String purchaseToken = inAppPurchaseDataBean.getPurchaseToken();
String productId = inAppPurchaseDataBean.getProductId();
if (DeliveryUtils.isDelivered(ConsumptionActivity.this, purchaseToken)) {
Toast.makeText(this, productId + " has been delivered", Toast.LENGTH_SHORT).show();
IapRequestHelper.consumeOwnedPurchase(mClient, purchaseToken);
} else {
if (DeliveryUtils.deliverProduct(this, productId, purchaseToken)) {
Log.verbose(TAG + "delivery success");
Toast.makeText(this, productId + " delivery success", Toast.LENGTH_SHORT).show();
// updateNumberOfGems();
// To consume the product after successfully delivering.
IapRequestHelper.consumeOwnedPurchase(mClient, purchaseToken);
} else {
Log.error(TAG + productId + " delivery fail");
Toast.makeText(this, productId + " delivery fail", Toast.LENGTH_SHORT).show();
}
}
} catch (JSONException e) {
Log.error(TAG + "delivery:" + e.getMessage());
}
} else {
// Log.e(TAG, "delivery:" + getString(R.string.verify_signature_fail));
// Toast.makeText(this, getString(R.string.verify_signature_fail), Toast.LENGTH_SHORT).show();
}
}
private void buy(int index)
{
ProductInfo productInfo = consumableProducts.get(index);
IapRequestHelper.createPurchaseIntent(mClient, productInfo.getProductId(), IapClient.PriceType.IN_APP_CONSUMABLE, new IapApiCallback<PurchaseIntentResult>() {
@Override
public void onSuccess(PurchaseIntentResult result) {
if (result == null) {
Log.error(TAG + "result is null");
return;
}
Status status = result.getStatus();
if (status == null) {
Log.error(TAG + "status is null");
return;
}
// You should pull up the page to complete the payment process.
IapRequestHelper.startResolutionForResult(ConsumptionActivity.this, status, Constants.REQ_CODE_BUY);
}
@Override
public void onFail(Exception e) {
int errorCode = ExceptionHandle.handle(ConsumptionActivity.this, e);
if (errorCode != ExceptionHandle.SOLVED) {
Log.error(TAG + "createPurchaseIntent, returnCode: " + errorCode);
switch (errorCode) {
case OrderStatusCode.ORDER_PRODUCT_OWNED:
queryPurchases(null);
break;
default:
break;
}
}
}
});
}
}
\ No newline at end of file
package com.Plugins.HuaweiSDK.activity;
import android.app.Activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.Plugins.HuaweiSDK.common.CipherUtil;
import com.Plugins.HuaweiSDK.common.IapApiCallback;
import com.Plugins.HuaweiSDK.common.Constants;
import com.Plugins.HuaweiSDK.common.ExceptionHandle;
import com.Plugins.HuaweiSDK.common.IapRequestHelper;
import com.Plugins.HuaweiSDK.common.DeliveryUtils;
import com.huawei.hms.iap.Iap;
import com.huawei.hms.iap.IapClient;
import com.huawei.hms.iap.entity.InAppPurchaseData;
import com.huawei.hms.iap.entity.IsEnvReadyResult;
import com.huawei.hms.iap.entity.OrderStatusCode;
import com.huawei.hms.iap.entity.OwnedPurchasesResult;
import com.huawei.hms.iap.util.IapClientHelper;
import com.huawei.hms.iap.entity.ProductInfo;
import com.huawei.hms.iap.entity.ProductInfoResult;
import com.huawei.hms.iap.entity.PurchaseIntentResult;
import com.huawei.hms.iap.entity.PurchaseResultInfo;
import com.huawei.hms.support.api.client.Status;
import org.json.JSONException;
import java.util.List;
import java.util.ArrayList;
public class EntryActivity extends AppCompatActivity
{
private static final String TAG = "EntryActivity";
private IapClient mClient;
private Activity mActivity;
private List<ProductInfo> consumableProducts = new ArrayList<ProductInfo>();
public EntryActivity(Activity activity)
{
mActivity = activity;
queryIsReady();
QueryPurchases(null);
}
private void queryIsReady()
{
mClient = Iap.getIapClient(mActivity);
IapRequestHelper.isEnvReady(mClient, new IapApiCallback<IsEnvReadyResult>()
{
@Override
public void onSuccess(IsEnvReadyResult result) {
nativeGetIapClientResult(true);
}
@Override
public void onFail(Exception e)
{
nativeGetIapClientResult(false);
ExceptionHandle.handle(mActivity, e);
}
});
}
public void QueryProducts()
{
List<String> productIds = new ArrayList<String>();
productIds.add("rmvw2021_coin_1");
productIds.add("rmvw2021_coin_2");
productIds.add("rmvw2021_coin_3");
productIds.add("rmvw2021_coin_4");
productIds.add("rmvw2021_coin_5");
productIds.add("rmvw2021_coin_6");
IapRequestHelper.obtainProductInfo(mClient, productIds, IapClient.PriceType.IN_APP_CONSUMABLE, new IapApiCallback<ProductInfoResult>() {
@Override
public void onSuccess(ProductInfoResult result) {
Log.i(TAG, "QueryProductsobtainProductInfo, success");
if (result == null) {
nativeQueryProductsResult(false);
return;
}
if (result.getProductInfoList() != null) {
consumableProducts = result.getProductInfoList();
Log.i(TAG, "consumableProducts->" + consumableProducts.toArray().length);
}
nativeQueryProductsResult(true);
}
@Override
public void onFail(Exception e) {
Log.e(TAG, "QueryProducts->obtainProductInfo: " + e.getMessage());
ExceptionHandle.handle(mActivity, e);
nativeQueryProductsResult(false);
}
});
}
private void QueryPurchases(String continuationToken)
{
final String tag = "obtainOwnedPurchases";
IapRequestHelper.obtainOwnedPurchases(mClient, IapClient.PriceType.IN_APP_CONSUMABLE, continuationToken, new IapApiCallback<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
if (result == null) {
Log.e(TAG, tag + " result is null");
return;
}
Log.i(TAG, "obtainOwnedPurchases, success");
if (result.getInAppPurchaseDataList() != null) {
List<String> inAppPurchaseDataList = result.getInAppPurchaseDataList();
List<String> inAppSignature= result.getInAppSignature();
for (int i = 0; i < inAppPurchaseDataList.size(); i++) {
final String inAppPurchaseData = inAppPurchaseDataList.get(i);
final String inAppPurchaseDataSignature = inAppSignature.get(i);
DeliverProduct(inAppPurchaseData, inAppPurchaseDataSignature);
}
}
if (!TextUtils.isEmpty(result.getContinuationToken())) {
QueryPurchases(result.getContinuationToken());
}
}
@Override
public void onFail(Exception e) {
Log.e(TAG, "obtainOwnedPurchases, type=" + IapClient.PriceType.IN_APP_CONSUMABLE + ", " + e.getMessage());
ExceptionHandle.handle(mActivity, e);
}
});
}
public void Payment(String productId) {
ProductInfo productInfo = null;
for (int i = 0; i < consumableProducts.toArray().length; i++)
{
Log.i(TAG, productId + " == " + consumableProducts.get(i).getProductId());
if (productId.equals(consumableProducts.get(i).getProductId()))
{
productInfo = consumableProducts.get(i);
break;
}
}
IapRequestHelper.createPurchaseIntent(mClient, productInfo.getProductId(), IapClient.PriceType.IN_APP_CONSUMABLE, new IapApiCallback<PurchaseIntentResult>() {
@Override
public void onSuccess(PurchaseIntentResult result) {
if (result == null) {
Log.e(TAG, "result is null");
return;
}
Status status = result.getStatus();
if (status == null) {
Log.e(TAG, "status is null");
return;
}
// You should pull up the page to complete the payment process.
IapRequestHelper.startResolutionForResult(mActivity, status, Constants.REQ_CODE_BUY);
}
@Override
public void onFail(Exception e) {
int errorCode = ExceptionHandle.handle(mActivity, e);
if (errorCode != ExceptionHandle.SOLVED) {
Log.e(TAG, "createPurchaseIntent, returnCode: " + errorCode);
switch (errorCode) {
case OrderStatusCode.ORDER_PRODUCT_OWNED:
// queryPurchases(null);
break;
default:
break;
}
}
}
});
}
private void DeliverProduct(final String inAppPurchaseDataStr, final String inAppPurchaseDataSignature)
{
if (CipherUtil.doCheck(inAppPurchaseDataStr, inAppPurchaseDataSignature, CipherUtil.getPublicKey())) {
// if (true){
try {
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseDataStr);
if (inAppPurchaseDataBean.getPurchaseState() != InAppPurchaseData.PurchaseState.PURCHASED) {
return;
}
String purchaseToken = inAppPurchaseDataBean.getPurchaseToken();
String productId = inAppPurchaseDataBean.getProductId();
if (DeliveryUtils.isDelivered(mActivity, purchaseToken)) {
Toast.makeText(mActivity, productId + " has been delivered", Toast.LENGTH_SHORT).show();
IapRequestHelper.consumeOwnedPurchase(mClient, purchaseToken);
} else {
if (DeliveryUtils.deliverProduct(mActivity, productId, purchaseToken)) {
Log.i(TAG, "delivery success");
Toast.makeText(mActivity, productId + " delivery success", Toast.LENGTH_SHORT).show();
// updateNumberOfGems();
// To consume the product after successfully delivering.
nativePaymentResult(purchaseToken, productId);
IapRequestHelper.consumeOwnedPurchase(mClient, purchaseToken);
} else {
Log.e(TAG, productId + " delivery fail");
Toast.makeText(mActivity, productId + " delivery fail", Toast.LENGTH_SHORT).show();
}
}
} catch (JSONException e) {
Log.e(TAG, "delivery:" + e.getMessage());
}
} else {
Log.e(TAG, "delivery:" + "getString(R.string.verify_signature_fail)");
Toast.makeText(mActivity, "getString(R.string.verify_signature_fail)", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
Log.i(TAG,"onActivityResult, resultCode: " + resultCode);
if (requestCode == Constants.REQ_CODE_BUY) {
if (data == null) {
Log.e(TAG, "data is null");
return;
}
PurchaseResultInfo purchaseIntentResult = Iap.getIapClient(mActivity).parsePurchaseResultInfoFromIntent(data);
switch(purchaseIntentResult.getReturnCode()) {
case OrderStatusCode.ORDER_STATE_CANCEL:
Toast.makeText(mActivity, "Order has been canceled!", Toast.LENGTH_SHORT).show();
break;
case OrderStatusCode.ORDER_STATE_FAILED:
case OrderStatusCode.ORDER_PRODUCT_OWNED:
QueryPurchases(null);
break;
case OrderStatusCode.ORDER_STATE_SUCCESS:
DeliverProduct(purchaseIntentResult.getInAppPurchaseData(), purchaseIntentResult.getInAppDataSignature());
break;
default:
break;
}
return;
}
}
public native void nativeGetIapClientResult(boolean success);
public native void nativeQueryProductsResult(boolean success);
public native void nativePaymentResult(String purchaseToken, String productId);
}
\ No newline at end of file
package com.Plugins.HuaweiSDK.activity;
import android.support.annotation.Keep;
import android.util.Log;
@Keep
public class Test
{
@Keep
public static String Test(String text)
{
text += " on Android";
Log.i("TEST", text);
return text;
}
}
package com.Plugins.HuaweiSDK.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.huawei.hms.iap.IapClient;
import com.huawei.hms.iap.entity.ProductInfo;
import java.util.List;
public class ProductListAdapter extends BaseAdapter
{
private Context mContext;
private List<ProductInfo> productInfos;
public ProductListAdapter(Context context, List<ProductInfo> productInfos) {
mContext = context;
this.productInfos = productInfos;
}
@Override
public int getCount() { return productInfos.size(); }
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ProductInfo productInfo = productInfos.get(position);
ProductListViewHolder holder = null;
if (null == convertView) {
// convertView = LayoutInflater.from(mContext).inflate(R.layout.item_layout, null);
holder = new ProductListViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ProductListViewHolder) convertView.getTag();
}
holder.productName.setText(productInfo.getProductName());
holder.productPrice.setText(productInfo.getPrice());
if (productInfo.getPriceType() == IapClient.PriceType.IN_APP_NONCONSUMABLE) {
holder.imageView.setVisibility(View.GONE);
}
return convertView;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public Object getItem(int position) {
if (productInfos != null && productInfos.size() > 0) {
return productInfos.get(position);
}
return null;
}
static class ProductListViewHolder {
TextView productName;
TextView productPrice;
ImageView imageView;
ProductListViewHolder(View view) {
// productName = (TextView) view.findViewById(R.id.item_name);
// productPrice = (TextView) view.findViewById(R.id.item_price);
// imageView = (ImageView) view.findViewById(R.id.item_image);
}
}
}
\ No newline at end of file
package com.Plugins.HuaweiSDK.common;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
public class CipherUtil
{
private static final String TAG = "CipherUtil";
private static final String SIGN_ALGORITHMS = "SHA256WithRSA";
private static final String PUBLIC_KEY = "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAm8mXjkmcrjAyybmhiZYNP4/QbRLvqerXVDur5NJ94qRQgXvCN3JL+E14ECb0bTu+N498Dc7ENfBusu/6vcwgDfsfeRewVwxzZUYJAZMTeuxBTR12gw0787A9dzyyf2YU6stinXyNyj8fmGiUI7htgfdIEmw2bOPTdWalIaTEjG2bMPFwhNbBaZJpFyLBkEMwgmujv/NLrZMxm4YKppyEkPyPCD2O8JARmoo++F8bgzI4lSXhE5s0bqceRl7TgYV3jnZbdxNT2FhBvZbIuk27gPy5oOQrJKsTl6yMQctpOK7T+x9uWNiw8nTUkZa1T6cUHJWxbRzQJ6aU8yE9lkV8rzFBqRharWG5lWJ3rJ6sPmW+xh8LVJpDRxUY5w0rBEWQ+f6h1xFnxNOT0fwNL7R+6cf7Mtyjpz6HoJok7n1dlg9oYsRd7XekLrpzyBlqi72tEQMeksJfOq3jm6FdBjEshc1gLEcn4nVP+ccpMFLcHpmC2uAGElJiiwNX8+yJxEiZAgMBAAE=";
/**
* the method to check the signature for the data returned from the interface
* @param content Unsigned data
* @param sign the signature for content
* @param publicKey the public of the application
* @return boolean
*/
public static boolean doCheck(String content, String sign, String publicKey) {
if (TextUtils.isEmpty(publicKey)) {
Log.e(TAG, "publicKey is null");
return false;
}
if (TextUtils.isEmpty(content) || TextUtils.isEmpty(sign)) {
Log.e(TAG, "data is error");
return false;
}
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.decode(publicKey, Base64.DEFAULT);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
signature.initVerify(pubKey);
signature.update(content.getBytes("utf-8"));
boolean bverify = signature.verify(Base64.decode(sign, Base64.DEFAULT));
Log.i(TAG, "doCheck bverify => " + bverify);
return bverify;
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "doCheck NoSuchAlgorithmException" + e);
} catch (InvalidKeySpecException e) {
Log.e(TAG, "doCheck InvalidKeySpecException" + e);
} catch (InvalidKeyException e) {
Log.e(TAG, "doCheck InvalidKeyException" + e);
} catch (SignatureException e) {
Log.e(TAG, "doCheck SignatureException" + e);
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "doCheck UnsupportedEncodingException" + e);
}
return false;
}
/**
* get the publicKey of the application
* During the encoding process, avoid storing the public key in clear text.
* @return publickey
*/
public static String getPublicKey(){
return PUBLIC_KEY;
}
}
\ No newline at end of file
package com.Plugins.HuaweiSDK.common;
public class Constants
{
/** requestCode for pull up the pmsPay page */
public static final int REQ_CODE_BUY = 4002;
/** requestCode for pull up the login page for isEnvReady interface */
public static final int REQ_CODE_LOGIN = 2001;
}
\ No newline at end of file
package com.Plugins.HuaweiSDK.common;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import java.util.HashSet;
import java.util.Set;
public class DeliveryUtils
{
private static final String PURCHASETOKEN_KEY = "purchasetokenSet";
private static final String GEMS_COUNT_KEY = "gemsCount";
private static final String DATA_NAME = "database";
public static boolean isDelivered(Context context, String purchasetoken) {
SharedPreferences sharedPreferences = context.getSharedPreferences(DATA_NAME, Context.MODE_PRIVATE);
Set<String> stringSet = sharedPreferences.getStringSet(PURCHASETOKEN_KEY, null);
if (stringSet != null && stringSet.contains(purchasetoken)) {
return true;
}
return false;
}
/**
* Ship and return the shipping result.
* @param context Context.
* @param productId Id of the purchased product.
* @param purchaseToken Generated by the Huawei payment server during product payment and returned to the app through InAppPurchaseData.
* @return boolean
*/
public static boolean deliverProduct(Context context, String productId, String purchaseToken) {
if (TextUtils.isEmpty(productId) || TextUtils.isEmpty(purchaseToken)) {
return false;
}
// if (!getNumOfGems().containsKey(productId)) {
// return false;
// }
SharedPreferences sharedPreferences = context.getSharedPreferences(DATA_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
// long count = sharedPreferences.getLong(GEMS_COUNT_KEY, 0);
// count += getNumOfGems().get(productId);
// editor.putLong(GEMS_COUNT_KEY, count);
Set<String> stringSet = sharedPreferences.getStringSet(PURCHASETOKEN_KEY, new HashSet<String>());
stringSet.add(purchaseToken);
editor.putStringSet(PURCHASETOKEN_KEY, stringSet);
return editor.commit();
}
}
\ No newline at end of file
package com.Plugins.HuaweiSDK.common;
import android.app.Activity;
import android.util.Log;
import android.widget.Toast;
import com.huawei.hms.iap.IapApiException;
import com.huawei.hms.iap.entity.OrderStatusCode;
import static android.content.ContentValues.TAG;
public class ExceptionHandle
{
public static final int SOLVED = 0;
/**
* Handles the exception returned from the iap api.
* @param activity The Activity to call the iap api.
* @param e The exception returned from the iap api.
* @return int
*/
public static int handle(Activity activity, Exception e) {
if (e instanceof IapApiException) {
IapApiException iapApiException = (IapApiException) e;
Log.i(TAG, "returnCode: " + iapApiException.getStatusCode());
switch (iapApiException.getStatusCode()) {
case OrderStatusCode.ORDER_STATE_CANCEL:
Toast.makeText(activity, "Order has been canceled!", Toast.LENGTH_SHORT).show();
return SOLVED;
case OrderStatusCode.ORDER_STATE_PARAM_ERROR:
Toast.makeText(activity, "Order state param error!", Toast.LENGTH_SHORT).show();
return SOLVED;
case OrderStatusCode.ORDER_STATE_NET_ERROR:
Toast.makeText(activity, "Order state net error!", Toast.LENGTH_SHORT).show();
return SOLVED;
case OrderStatusCode.ORDER_VR_UNINSTALL_ERROR:
Toast.makeText(activity, "Order vr uninstall error!", Toast.LENGTH_SHORT).show();
return SOLVED;
case OrderStatusCode.ORDER_HWID_NOT_LOGIN:
IapRequestHelper.startResolutionForResult(activity, iapApiException.getStatus(), Constants.REQ_CODE_LOGIN);
return SOLVED;
case OrderStatusCode.ORDER_PRODUCT_OWNED:
Toast.makeText(activity, "Product already owned error!", Toast.LENGTH_SHORT).show();
return OrderStatusCode.ORDER_PRODUCT_OWNED;
case OrderStatusCode.ORDER_PRODUCT_NOT_OWNED:
Toast.makeText(activity, "Product not owned error!", Toast.LENGTH_SHORT).show();
return SOLVED;
case OrderStatusCode.ORDER_PRODUCT_CONSUMED:
Toast.makeText(activity, "Product consumed error!", Toast.LENGTH_SHORT).show();
return SOLVED;
case OrderStatusCode.ORDER_ACCOUNT_AREA_NOT_SUPPORTED:
Toast.makeText(activity, "Order account area not supported error!", Toast.LENGTH_SHORT).show();
return SOLVED;
case OrderStatusCode.ORDER_NOT_ACCEPT_AGREEMENT:
Toast.makeText(activity, "User does not agree the agreement", Toast.LENGTH_SHORT).show();
return SOLVED;
default:
// handle other error scenarios
Toast.makeText(activity, "Order unknown error! " + iapApiException.getStatusCode(), Toast.LENGTH_SHORT).show();
return SOLVED;
}
} else {
Toast.makeText(activity, "external error", Toast.LENGTH_SHORT).show();
Log.e(TAG, e.getMessage());
return SOLVED;
}
}
}
\ No newline at end of file
package com.Plugins.HuaweiSDK.common;
public interface IapApiCallback<T> {
/**
* The request is successful.
* @param result The result of a successful response.
*/
void onSuccess(T result);
/**
* Callback fail.
* @param e An Exception from IAPSDK.
*/
void onFail(Exception e);
}
\ No newline at end of file
package com.Plugins.HuaweiSDK.common;
import android.app.Activity;
import android.content.IntentSender;
import android.text.TextUtils;
import android.util.Log;
import com.huawei.hmf.tasks.OnFailureListener;
import com.huawei.hmf.tasks.OnSuccessListener;
import com.huawei.hmf.tasks.Task;
import com.huawei.hms.iap.Iap;
import com.huawei.hms.iap.IapApiException;
import com.huawei.hms.iap.IapClient;
import com.huawei.hms.iap.entity.ConsumeOwnedPurchaseReq;
import com.huawei.hms.iap.entity.ConsumeOwnedPurchaseResult;
import com.huawei.hms.iap.entity.IsEnvReadyResult;
import com.huawei.hms.iap.entity.OwnedPurchasesReq;
import com.huawei.hms.iap.entity.OwnedPurchasesResult;
import com.huawei.hms.iap.entity.ProductInfoReq;
import com.huawei.hms.iap.entity.ProductInfoResult;
import com.huawei.hms.iap.entity.PurchaseIntentReq;
import com.huawei.hms.iap.entity.PurchaseIntentResult;
import com.huawei.hms.support.api.client.Status;
import java.util.List;
public class IapRequestHelper {
private final static String TAG = "IapRequestHelper";
/**
* Create a PurchaseIntentReq object.
* @param type In-app product type.
* The value contains: 0: consumable 1: non-consumable 2 auto-renewable subscription
* @param productId ID of the in-app product to be paid.
* The in-app product ID is the product ID you set during in-app product configuration in AppGallery Connect.
* @return PurchaseIntentReq
*/
private static PurchaseIntentReq createPurchaseIntentReq(int type, String productId) {
PurchaseIntentReq req = new PurchaseIntentReq();
req.setPriceType(type);
req.setProductId(productId);
req.setDeveloperPayload("testPurchase");
return req;
}
/**
* Create a OwnedPurchasesReq object.
* @param type type In-app product type.
* The value contains: 0: consumable 1: non-consumable 2 auto-renewable subscription
* @param continuationToken A data location flag which returns from obtainOwnedPurchases api or obtainOwnedPurchaseRecord api.
* @return OwnedPurchasesReq
*/
private static OwnedPurchasesReq createOwnedPurchasesReq(int type, String continuationToken) {
OwnedPurchasesReq req = new OwnedPurchasesReq();
req.setPriceType(type);
req.setContinuationToken(continuationToken);
return req;
}
/**
* Create a ProductInfoReq object.
* @param type In-app product type.
* The value contains: 0: consumable 1: non-consumable 2 auto-renewable subscription
* @param productIds ID list of products to be queried. Each product ID must exist and be unique in the current app.
* @return ProductInfoReq
*/
private static ProductInfoReq createProductInfoReq(int type, List<String> productIds) {
ProductInfoReq req = new ProductInfoReq();
req.setPriceType(type);
req.setProductIds(productIds);
return req;
}
/**
* To check whether the country or region of the logged in HUAWEI ID is included in the countries or regions supported by HUAWEI IAP.
* @param mClient IapClient instance to call the isEnvReady API.
* @param callback IapApiCallback.
*/
public static void isEnvReady(IapClient mClient, final IapApiCallback callback) {
Log.i(TAG, "call isEnvReady");
Task<IsEnvReadyResult> task = mClient.isEnvReady();
task.addOnSuccessListener(new OnSuccessListener<IsEnvReadyResult>() {
@Override
public void onSuccess(IsEnvReadyResult result) {
Log.i(TAG, "isEnvReady, success");
callback.onSuccess(result);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "isEnvReady, fail");
callback.onFail(e);
}
});
}
/**
* Create a ConsumeOwnedPurchaseReq object.
* @param purchaseToken which is generated by the Huawei payment server during product payment and returned to the app through InAppPurchaseData.
* The app transfers this parameter for the Huawei payment server to update the order status and then deliver the in-app product.
* @return ConsumeOwnedPurchaseReq
*/
private static ConsumeOwnedPurchaseReq createConsumeOwnedPurchaseReq(String purchaseToken) {
ConsumeOwnedPurchaseReq req = new ConsumeOwnedPurchaseReq();
req.setPurchaseToken(purchaseToken);
req.setDeveloperChallenge("testConsume");
return req;
}
/**
* Obtain in-app product details configured in AppGallery Connect.
* @param iapClient IapClient instance to call the obtainProductInfo API.
* @param productIds ID list of products to be queried. Each product ID must exist and be unique in the current app.
* @param type In-app product type.
* The value contains: 0: consumable 1: non-consumable 2 auto-renewable subscription
* @param callback IapApiCallback
*/
public static void obtainProductInfo(IapClient iapClient, final List<String> productIds, int type, final IapApiCallback callback) {
Log.i(TAG, "call obtainProductInfo");
Task<ProductInfoResult> task = iapClient.obtainProductInfo(createProductInfoReq(type, productIds));
task.addOnSuccessListener(new OnSuccessListener<ProductInfoResult>() {
@Override
public void onSuccess(ProductInfoResult result) {
Log.i(TAG, "obtainProductInfo, success");
callback.onSuccess(result);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "obtainProductInfo, fail");
callback.onFail(e);
}
});
}
/**
* create orders for in-app products in the PMS
* @param iapClient IapClient instance to call the createPurchaseIntent API.
* @param productId ID of the in-app product to be paid.
* The in-app product ID is the product ID you set during in-app product configuration in AppGallery Connect.
* @param type In-app product type.
* The value contains: 0: consumable 1: non-consumable 2 auto-renewable subscription
* @param callback IapApiCallback
*/
public static void createPurchaseIntent(final IapClient iapClient, String productId, int type, final IapApiCallback callback) {
Log.i(TAG, "call createPurchaseIntent");
Task<PurchaseIntentResult> task = iapClient.createPurchaseIntent(createPurchaseIntentReq(type, productId));
task.addOnSuccessListener(new OnSuccessListener<PurchaseIntentResult>() {
@Override
public void onSuccess(PurchaseIntentResult result) {
Log.i(TAG, "createPurchaseIntent, success");
callback.onSuccess(result);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "createPurchaseIntent, fail");
callback.onFail(e);
}
});
}
/**
* to start an activity.
* @param activity the activity to launch a new page.
* @param status This parameter contains the pendingIntent object of the payment page.
* @param reqCode Result code.
*/
public static void startResolutionForResult(Activity activity, Status status, int reqCode) {
if (status == null) {
Log.e(TAG, "status is null");
return;
}
if (status.hasResolution()) {
try {
status.startResolutionForResult(activity, reqCode);
} catch (IntentSender.SendIntentException exp) {
Log.e(TAG, exp.getMessage());
}
} else {
Log.e(TAG, "intent is null");
}
}
/**
* query information about all subscribed in-app products, including consumables, non-consumables, and auto-renewable subscriptions.</br>
* If consumables are returned, the system needs to deliver them and calls the consumeOwnedPurchase API to consume the products.
* If non-consumables are returned, the in-app products do not need to be consumed.
* If subscriptions are returned, all existing subscription relationships of the user under the app are returned.
* @param mClient IapClient instance to call the obtainOwnedPurchases API.
* @param type In-app product type.
* The value contains: 0: consumable 1: non-consumable 2 auto-renewable subscription
* @param callback IapApiCallback
*/
public static void obtainOwnedPurchases(IapClient mClient, final int type, String continuationToken, final IapApiCallback callback) {
Log.i(TAG, "call obtainOwnedPurchases");
Task<OwnedPurchasesResult> task = mClient.obtainOwnedPurchases(IapRequestHelper.createOwnedPurchasesReq(type, continuationToken));
task.addOnSuccessListener(new OnSuccessListener<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
Log.i(TAG, "obtainOwnedPurchases, success");
callback.onSuccess(result);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "obtainOwnedPurchases, fail");
callback.onFail(e);
}
});
}
/**
* Consume all the unconsumed purchases with priceType 0.
* @param iapClient IapClient instance to call the consumeOwnedPurchase API.
* @param purchaseToken which is generated by the Huawei payment server during product payment and returned to the app through InAppPurchaseData.
*/
public static void consumeOwnedPurchase(IapClient iapClient, String purchaseToken) {
Log.i(TAG, "call consumeOwnedPurchase");
Task<ConsumeOwnedPurchaseResult> task = iapClient.consumeOwnedPurchase(createConsumeOwnedPurchaseReq(purchaseToken));
task.addOnSuccessListener(new OnSuccessListener<ConsumeOwnedPurchaseResult>() {
@Override
public void onSuccess(ConsumeOwnedPurchaseResult result) {
// Consume success.
Log.i(TAG, "consumeOwnedPurchase success");
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
int returnCode = apiException.getStatusCode();
Log.e(TAG, "consumeOwnedPurchase fail, IapApiException returnCode: " + returnCode);
} else {
// Other external errors
Log.e(TAG, e.getMessage());
}
}
});
}
}
\ No newline at end of file
#include "AndroidUtils.h"
/**
* Template functions must be in .h
*/
\ No newline at end of file
#pragma once
#include <Android/AndroidJNI.h>
#include <Android/AndroidApplication.h>
#include <Android/AndroidJava.h>
#include "JavaConvert.h"
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class AndroidUtils
{
public:
//-- Free memory
static bool DeleteJavaObject(jobject JavaObject)
{
if (JavaObject){
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
Env->DeleteLocalRef(JavaObject);
JavaObject = nullptr;
return 1;
}
return 0;
}
// -- Why do we need this structure?
// -- https://stackoverflow.com/questions/47373354/c-void-argument-with-variadic-template
template <typename T>
struct type { };
template<typename anyType>
static const anyType& convertArg(const anyType& value)
{
return value;
}
static jstring convertArg(const char* str)
{
return JavaConvert::GetJavaString(str);
}
static jstring convertArg(std::string str)
{
return JavaConvert::GetJavaString(str);
}
static jstring convertArg(FString str)
{
return JavaConvert::GetJavaString(str);
}
static jlong convertArg(long l)
{
return JavaConvert::GetJavaLong(l);
}
//---array
static jobjectArray convertArg(TArray<const char*> stringArray)
{
TArray<FString> tmpFString;
for (auto tmpCellStringArray : stringArray) {
std::string tmpString = tmpCellStringArray;
tmpFString.Add(tmpString.c_str());
}
return JavaConvert::ConvertToJStringArray(tmpFString);
}
static jobjectArray convertArg(TArray<std::string> stringArray)
{
TArray<FString> tmpFString;
for (auto tmpCellStringArray : stringArray)
tmpFString.Add(tmpCellStringArray.c_str());
return JavaConvert::ConvertToJStringArray(tmpFString);
}
static jobjectArray convertArg(TArray<FString> stringArray)
{
return JavaConvert::ConvertToJStringArray(stringArray);
}
static jbooleanArray convertArg(TArray<bool> boolArray)
{
return JavaConvert::ConvertToJBooleanArray(boolArray);
}
static jintArray convertArg(TArray<int> intArray)
{
return JavaConvert::ConvertToJIntArray(intArray);
}
static jbyteArray convertArg(TArray<uint8> byteArray)
{
return JavaConvert::ConvertToJByteArray(byteArray);
}
static jlongArray convertArg(TArray<long> longArray)
{
return JavaConvert::ConvertToJLongArray(longArray);
}
static jfloatArray convertArg(TArray<float> floatArray)
{
return JavaConvert::ConvertToJFloatArray(floatArray);
}
///=============== Override Tempalte===========================
static std::string GetTypeName(void)
{
return "V";
}
static std::string GetTypeName(bool b)
{
return "Z";
}
static std::string GetTypeName(unsigned char uc)
{
return "B";
}
static std::string GetTypeName(char c)
{
return "C";
}
static std::string GetTypeName(short s)
{
return "S";
}
static std::string GetTypeName(int i)
{
return "I";
}
static std::string GetTypeName(unsigned int i)
{
return "I";
}
static std::string GetTypeName(long l)
{
return "J";
}
static std::string GetTypeName(float f)
{
return "F";
}
static std::string GetTypeName(double d)
{
return "D";
}
static std::string GetTypeName(const char* str)
{
return "Ljava/lang/String;";
}
static std::string GetTypeName(std::string str)
{
return "Ljava/lang/String;";
}
static std::string GetTypeName(FString str)
{
return "Ljava/lang/String;";
}
static std::string GetTypeName(jstring str)
{
return "Ljava/lang/String;";
}
static std::string GetTypeName(jobject jo)
{
return "Ljava/lang/Object;";
}
//----array
static std::string GetTypeName(jobjectArray joa)
{
return "[Ljava/lang/Object;";
}
template<typename anyType>
static std::string GetTypeName(TArray<anyType> anyArr) {
anyType SymbolType{};
return std::string("[" + GetTypeName(SymbolType));
}
template<typename anyType>
static std::string GetTypeName(std::vector<anyType> anyArr) {
anyType SymbolType{};
return std::string("[" + GetTypeName(SymbolType));
}
///=============== Recursion Method for Variadic Template===========================
// ------------ GetType
template<typename anyType, typename ...Args>
static void GetType(std::string& signatureString, anyType value, Args ...args)
{
signatureString += GetTypeName(value);
GetType(signatureString, args...);
}
// ------------ GetType
static void GetType(std::string&) { }
///=============== Call Target Jni ========================================
//========== UserObjectClass ==============
static void CallJniVoidMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallJniVoidMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = FAndroidApplication::FindJavaClass(ClassName);
jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
Env->CallStaticVoidMethodV(Class, Method, Args);
va_end(Args);
Env->DeleteLocalRef(Class);
}
static FString CallJniStringMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallJniStringMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = FAndroidApplication::FindJavaClass(ClassName);
jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jstring Return = static_cast<jstring>(Env->CallStaticObjectMethodV(Class, Method, Args));
va_end(Args);
const char* UTFString = Env->GetStringUTFChars(Return, nullptr);
FString Result(UTF8_TO_TCHAR(UTFString));
Env->ReleaseStringUTFChars(Return, UTFString);
Env->DeleteLocalRef(Class);
return Result;
}
static bool CallJniBoolMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallJniBoolMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = FAndroidApplication::FindJavaClass(ClassName);
jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
bool Result = Env->CallStaticBooleanMethodV(Class, Method, Args);
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
static int CallJniIntMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallJniIntMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = FAndroidApplication::FindJavaClass(ClassName);
jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
int Result = Env->CallStaticIntMethodV(Class, Method, Args);
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
static long CallJniLongMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallJniLongMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = FAndroidApplication::FindJavaClass(ClassName);
jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
long Result = Env->CallStaticLongMethodV(Class, Method, Args);
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
static jobject CallJniObjectMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallJniObjectMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = FAndroidApplication::FindJavaClass(ClassName);
jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jobject Result = Env->CallStaticObjectMethodV(Class, Method, Args);
va_end(Args);
Env->DeleteLocalRef(Class);
if (!Result)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
return Result;
}
static jobjectArray CallJniObjectArrayMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallJniObjectArray [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = FAndroidApplication::FindJavaClass(ClassName);
jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jobjectArray Result = static_cast<jobjectArray>(Env->CallStaticObjectMethodV(Class, Method, Args));
va_end(Args);
Env->DeleteLocalRef(Class);
if (!Result)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobjectArray = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
return Result;
}
static jfloatArray CallJniFloatArrayMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallJniFloatArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = FAndroidApplication::FindJavaClass(ClassName);
jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jfloatArray Result = static_cast<jfloatArray>(Env->CallStaticObjectMethodV(Class, Method, Args));
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
static jintArray CallJniIntArrayMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallJniIntArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = FAndroidApplication::FindJavaClass(ClassName);
jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jintArray Result = static_cast<jintArray>(Env->CallStaticObjectMethodV(Class, Method, Args));
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
static jlongArray CallJniLongArrayMethod(const ANSICHAR* ClassName, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallJniLongArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = FAndroidApplication::FindJavaClass(ClassName);
jmethodID Method = FJavaWrapper::FindStaticMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jlongArray Result = static_cast<jlongArray>(Env->CallStaticObjectMethodV(Class, Method, Args));
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
//========== JavaObjectClass ==============
static void CallObjectJniVoidMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallObjectJniVoidMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
if (!object)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = Env->GetObjectClass(object);
jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
Env->CallVoidMethodV(object, Method, Args);
va_end(Args);
Env->DeleteLocalRef(Class);
}
static FString CallObjectJniStringMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallObjectJniStringMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
if (!object)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = Env->GetObjectClass(object);
jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jstring Return = static_cast<jstring>(Env->CallObjectMethodV(object, Method, Args));
va_end(Args);
const char* UTFString = Env->GetStringUTFChars(Return, nullptr);
FString Result(UTF8_TO_TCHAR(UTFString));
Env->ReleaseStringUTFChars(Return, UTFString);
Env->DeleteLocalRef(Class);
return Result;
}
static bool CallObjectJniBoolMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallObjectJniBoolMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
if (!object)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = Env->GetObjectClass(object);
jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
bool Result = Env->CallBooleanMethodV(object, Method, Args);
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
static int CallObjectJniIntMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallObjectJniIntMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
if (!object)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = Env->GetObjectClass(object);
jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
int Result = Env->CallIntMethodV(object, Method, Args);
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
static long CallObjectJniLongMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallObjectJniLongMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
if (!object)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = Env->GetObjectClass(object);
jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
long Result = Env->CallLongMethodV(object, Method, Args);
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
static jobject CallObjectJniObjectMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallObjectJniObjectMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
if (!object)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = Env->GetObjectClass(object);
jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jobject Result = Env->CallObjectMethodV(object, Method, Args);
va_end(Args);
Env->DeleteLocalRef(Class);
if(!Result)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: return jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
return Result;
}
static jobjectArray CallObjectJniObjectArrayMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallObjectJniObjectArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
if (!object)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = Env->GetObjectClass(object);
jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jobjectArray Result = static_cast<jobjectArray>(Env->CallObjectMethodV(object, Method, Args));
va_end(Args);
Env->DeleteLocalRef(Class);
if (!Result)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: return jobjectArray = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
return Result;
}
static jfloatArray CallObjectJniFloatArrayMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallObjectJniFloatArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
if (!object)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = Env->GetObjectClass(object);
jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jfloatArray Result = static_cast<jfloatArray>(Env->CallObjectMethodV(object, Method, Args));
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
static jintArray CallObjectJniIntArrayMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallObjectJniIntArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
if (!object)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = Env->GetObjectClass(object);
jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jintArray Result = static_cast<jintArray>(Env->CallObjectMethodV(object, Method, Args));
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
static jlongArray CallObjectJniLongArrayMethod(jobject object, const ANSICHAR* MethodName, const ANSICHAR* MethodSignature, ...)
{
UE_LOG(LogTemp, Warning, TEXT("MobileNativeCode -> Method CallObjectJniLongArrayMethod [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
if (!object)
UE_LOG(LogTemp, Error, TEXT("MobileNativeCode -> Err: jobject = null [%s][%s]"), *FString(MethodName), *FString(MethodSignature));
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jclass Class = Env->GetObjectClass(object);
jmethodID Method = FJavaWrapper::FindMethod(Env, Class, MethodName, MethodSignature, false);
va_list Args;
va_start(Args, MethodSignature);
jlongArray Result = static_cast<jlongArray>(Env->CallObjectMethodV(object, Method, Args));
va_end(Args);
Env->DeleteLocalRef(Class);
return Result;
}
///=============== Override Callback and Return JNI===========================
//========== UserObjectClass ==============
// ------------ void case
template <typename... Args>
static void isTypeJNI(type<void>, const char* ClassName, const char* FunctionName, std::string OverrideSignature, bool isActivity, Args ...args)
{
std::string MethodSignature;
if (OverrideSignature.empty()) {
MethodSignature = "(";
MethodSignature += isActivity ? "Landroid/app/Activity;" : "";
GetType(MethodSignature, args...);
MethodSignature += ")";
MethodSignature += GetTypeName();
}
else
{
MethodSignature = OverrideSignature;
}
if (isActivity)
CallJniVoidMethod(ClassName, FunctionName, MethodSignature.c_str(), FJavaWrapper::GameActivityThis, convertArg(args)...);
else
CallJniVoidMethod(ClassName, FunctionName, MethodSignature.c_str(), convertArg(args)...);
}
// ------------ non-void case
template <typename MethodType, typename... Args>
static MethodType isTypeJNI(type<MethodType>, const char* ClassName, const char* FunctionName, std::string OverrideSignature, bool isActivity, Args ...args)
{
MethodType returnType{};
std::string MethodSignature;
if (OverrideSignature.empty()) {
MethodSignature = "(";
MethodSignature += isActivity ? "Landroid/app/Activity;" : "";
GetType(MethodSignature, args...);
MethodSignature += ")";
MethodSignature += GetTypeName(returnType);
}
else
{
MethodSignature = OverrideSignature;
}
if (isActivity)
return CallJNI(returnType, ClassName, FunctionName, MethodSignature.c_str(), FJavaWrapper::GameActivityThis, convertArg(args)...);
else
return CallJNI(returnType, ClassName, FunctionName, MethodSignature.c_str(), convertArg(args)...);
}
// ------------ FString
template<typename ...Args>
static FString CallJNI(FString str, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallJniStringMethod(ClassName, MethodName, MethodSignature, args...);
}
// ------------ std::string
template<typename ...Args>
static std::string CallJNI(std::string str, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
FString TempStr = CallJniStringMethod(ClassName, MethodName, MethodSignature, args...);
return std::string(TCHAR_TO_UTF8(*TempStr));
}
// ------------ bool
template<typename ...Args>
static bool CallJNI(bool b, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallJniBoolMethod(ClassName, MethodName, MethodSignature, args...);
}
// ------------ int
template<typename ...Args>
static int CallJNI(int i, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallJniIntMethod(ClassName, MethodName, MethodSignature, args...);
}
// ------------ long
template<typename ...Args>
static long CallJNI(long l, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallJniLongMethod(ClassName, MethodName, MethodSignature, args...);
}
// ------------ jobject
template<typename ...Args>
static jobject CallJNI(jobject jo, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallJniObjectMethod(ClassName, MethodName, MethodSignature, args...);
}
// ------------ jobjectArray
template<typename ...Args>
static jobjectArray CallJNI(jobjectArray joa, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallJniObjectArrayMethod(ClassName, MethodName, MethodSignature, args...);
}
// ------------ TArray<FString>
template<typename ...Args>
static TArray<FString> CallJNI(TArray<FString> strArr, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
return JavaConvert::ConvertToStringArray(CallJniObjectArrayMethod(ClassName, MethodName, MethodSignature, args...));
}
// ------------ TArray<float>
template<typename ...Args>
static TArray<float> CallJNI(TArray<float> fArr, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
return JavaConvert::ConvertToFloatArray(CallJniFloatArrayMethod(ClassName, MethodName, MethodSignature, args...));
}
// ------------ TArray<int>
template<typename ...Args>
static TArray<int> CallJNI(TArray<int> iArr, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
return JavaConvert::ConvertToIntArray(CallJniIntArrayMethod(ClassName, MethodName, MethodSignature, args...));
}
// ------------ TArray<long>
template<typename ...Args>
static TArray<long> CallJNI(TArray<long> lArr, const char* ClassName, const char* MethodName, const char* MethodSignature, Args ...args)
{
return JavaConvert::ConvertToLongArray(CallJniLongArrayMethod(ClassName, MethodName, MethodSignature, args...));
}
//========== JavaObjectClass ==============
// ------------ void case object
template <typename... Args>
static void isTypeJNI(type<void>, jobject JavaObjectClass, const char* FunctionName, std::string OverrideSignature, Args ...args)
{
std::string MethodSignature;
if (OverrideSignature.empty()) {
MethodSignature = "(";
GetType(MethodSignature, args...);
MethodSignature += ")";
MethodSignature += GetTypeName();
}
else
{
MethodSignature = OverrideSignature;
}
CallObjectJniVoidMethod(JavaObjectClass, FunctionName, MethodSignature.c_str(), convertArg(args)...);
}
// ------------ non-void case object
template <typename MethodType, typename... Args>
static MethodType isTypeJNI(type<MethodType>, jobject JavaObjectClass, const char* FunctionName, std::string OverrideSignature, Args ...args)
{
MethodType returnType{};
std::string MethodSignature;
if (OverrideSignature.empty()) {
MethodSignature = "(";
GetType(MethodSignature, args...);
MethodSignature += ")";
MethodSignature += GetTypeName(returnType);
}
else
{
MethodSignature = OverrideSignature;
}
return CallObjectJNI(returnType, JavaObjectClass, FunctionName, MethodSignature.c_str(), convertArg(args)...);
}
// ------------ FString
template<typename ...Args>
static FString CallObjectJNI(FString str, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallObjectJniStringMethod(JavaObjectClass, MethodName, MethodSignature, args...);
}
// ------------ std::string
template<typename ...Args>
static std::string CallObjectJNI(std::string str, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
FString TempStr = CallObjectJniStringMethod(JavaObjectClass, MethodName, MethodSignature, args...);
return std::string(TCHAR_TO_UTF8(*TempStr));
}
// ------------ bool
template<typename ...Args>
static bool CallObjectJNI(bool b, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallObjectJniBoolMethod(JavaObjectClass, MethodName, MethodSignature, args...);
}
// ------------ int
template<typename ...Args>
static int CallObjectJNI(int i, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallObjectJniIntMethod(JavaObjectClass, MethodName, MethodSignature, args...);
}
// ------------ long
template<typename ...Args>
static long CallObjectJNI(long l, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallObjectJniLongMethod(JavaObjectClass, MethodName, MethodSignature, args...);
}
// ------------ jobject
template<typename ...Args>
static jobject CallObjectJNI(jobject jo, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallObjectJniObjectMethod(JavaObjectClass, MethodName, MethodSignature, args...);
}
// ------------ jobjectArray
template<typename ...Args>
static jobjectArray CallObjectJNI(jobjectArray joa, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
return CallObjectJniObjectArrayMethod(JavaObjectClass, MethodName, MethodSignature, args...);
}
// ------------ TArray<FString>
template<typename ...Args>
static TArray<FString> CallObjectJNI(TArray<FString> strArr, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
return JavaConvert::ConvertToStringArray(CallObjectJniObjectArrayMethod(JavaObjectClass, MethodName, MethodSignature, args...));
}
// ------------ TArray<float>
template<typename ...Args>
static TArray<float> CallObjectJNI(TArray<float> fArr, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
return JavaConvert::ConvertToFloatArray(CallObjectJniFloatArrayMethod(JavaObjectClass, MethodName, MethodSignature, args...));
}
// ------------ TArray<int>
template<typename ...Args>
static TArray<int> CallObjectJNI(TArray<int> iArr, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
return JavaConvert::ConvertToIntArray(CallObjectJniIntArrayMethod(JavaObjectClass, MethodName, MethodSignature, args...));
}
// ------------ TArray<long>
template<typename ...Args>
static TArray<long> CallObjectJNI(TArray<long> lArr, jobject JavaObjectClass, const char* MethodName, const char* MethodSignature, Args ...args)
{
return JavaConvert::ConvertToLongArray(CallObjectJniLongArrayMethod(JavaObjectClass, MethodName, MethodSignature, args...));
}
///============Calling native Android code from C++===============
/**
* @param ClassName - package (used by com/Plugins/MobileNativeCode) and the name of your Java class.
* @param FunctionName - Name of your Java function.
* @param OverrideSignature - Set your own signature instead of an automatic one (Send an empty one if you need an automatic one).
* @param isActivity - Determines whether to pass Activity UE4 to Java.
* @param args... - A list of your parameters in the Java function.
*/
template<typename MethodType, typename ...Args>
static MethodType CallJavaCode(const char* ClassName, const char* FunctionName, const char* OverrideSignature, bool isActivity, Args ...args)
{
return isTypeJNI(type<MethodType>{}, ClassName, FunctionName, OverrideSignature, isActivity, args...);
}
/**
* @param JavaObjectClass - the type of jobject from which you want to call a local Java function
* @param FunctionName - Name of your Java function.
* @param OverrideSignature - Set your own signature instead of an automatic one (Send an empty one if you need an automatic one).
* @param args... - A list of your parameters in the Java function.
*/
template<typename MethodType, typename ...Args>
static MethodType CallJavaCode(jobject JavaObjectClass, const char* FunctionName, const char* OverrideSignature, Args ...args)
{
return isTypeJNI(type<MethodType>{}, JavaObjectClass, FunctionName, OverrideSignature, args...);
}
};
#include "JavaConvert.h"
//==============Java Convert===================================
// TArray<FString> to jobjectArray
jobjectArray JavaConvert::ConvertToJStringArray(const TArray<FString>& stringArray)
{
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jobjectArray javaStringArray = (jobjectArray)Env->NewObjectArray(stringArray.Num(), FJavaWrapper::JavaStringClass, nullptr);
for (int i = 0; i < stringArray.Num(); i++) {
Env->SetObjectArrayElement(javaStringArray, i, JavaConvert::GetJavaString(stringArray[i]));
}
return javaStringArray;
}
// TArray<bool> to jbooleanArray
jbooleanArray JavaConvert::ConvertToJBooleanArray(const TArray<bool>& boolArray)
{
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jbooleanArray javaBooleanArray = (jbooleanArray)Env->NewBooleanArray(boolArray.Num());
jboolean* javaBooleanArrayPtr = Env->GetBooleanArrayElements(javaBooleanArray, 0);
for (int i = 0; i < boolArray.Num(); i++) {
javaBooleanArrayPtr[i] = boolArray[i];
}
return javaBooleanArray;
}
// TArray<int> to jintArray
jintArray JavaConvert::ConvertToJIntArray(const TArray<int>& intArray)
{
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jintArray javaIntArray = (jintArray)Env->NewIntArray(intArray.Num());
jint* javaIntArrayPtr = (jint*)malloc(intArray.Num() * sizeof(jint));
for (int i = 0; i < intArray.Num(); i++) {
javaIntArrayPtr[i] = (jint)intArray[i];
}
Env->SetIntArrayRegion(javaIntArray, 0, intArray.Num(), javaIntArrayPtr);
free(javaIntArrayPtr);
return javaIntArray;
}
// TArray<unsigned char> to jbyteArray
jbyteArray JavaConvert::ConvertToJByteArray(const TArray<uint8>& byteArray)
{
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jbyteArray javaByteArray = (jbyteArray)Env->NewByteArray(byteArray.Num());
jbyte* javaByteArrayPtr = (jbyte*)malloc(byteArray.Num() * sizeof(jbyte));
for (int i = 0; i < byteArray.Num(); i++) {
javaByteArrayPtr[i] = byteArray[i];
}
Env->SetByteArrayRegion(javaByteArray, 0, byteArray.Num(), javaByteArrayPtr);
free(javaByteArrayPtr);
return javaByteArray;
}
// TArray<long> to jlongArray
jlongArray JavaConvert::ConvertToJLongArray(const TArray<long>& longArray)
{
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jlongArray javaLongArray = (jlongArray)Env->NewLongArray(longArray.Num());
jlong* javaLongArrayPtr = (jlong*)malloc(longArray.Num() * sizeof(jlong));
for (int i = 0; i < longArray.Num(); i++) {
javaLongArrayPtr[i] = longArray[i];
}
Env->SetLongArrayRegion(javaLongArray, 0, longArray.Num(), javaLongArrayPtr);
free(javaLongArrayPtr);
return javaLongArray;
}
// TArray<float> to jfloatArray
jfloatArray JavaConvert::ConvertToJFloatArray(const TArray<float>& floatArray)
{
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jfloatArray javaFloatArray = (jfloatArray)Env->NewFloatArray(floatArray.Num());
jfloat* javaFloatArrayPtr = (jfloat*)malloc(floatArray.Num() * sizeof(jfloat));
for (int i = 0; i < floatArray.Num(); i++) {
javaFloatArrayPtr[i] = floatArray[i];
}
Env->SetFloatArrayRegion(javaFloatArray, 0, floatArray.Num(), javaFloatArrayPtr);
free(javaFloatArrayPtr);
return javaFloatArray;
}
// jbyteArray to TArray<unsigned char>
TArray<uint8> JavaConvert::ConvertToByteArray(jbyteArray javaArray)
{
TArray<uint8> byteArray;
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jbyte* javaByte = Env->GetByteArrayElements(javaArray, 0);
int length = Env->GetArrayLength(javaArray);
for (int i = 0; i < length; i++) {
byteArray.Add(javaByte[i]);
}
return byteArray;
}
// jfloatArray to TArray<float>
TArray<float> JavaConvert::ConvertToFloatArray(jfloatArray javaArray)
{
TArray<float> floatArray;
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jfloat* javaFloat = Env->GetFloatArrayElements(javaArray, 0);
int length = Env->GetArrayLength(javaArray);
for (int i = 0; i < length; i++)
{
floatArray.Add((float)javaFloat[i]);
}
return floatArray;
}
// jintArray to TArray<int>
TArray<int> JavaConvert::ConvertToIntArray(jintArray javaArray)
{
TArray<int> numArray;
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jint* javaNum = Env->GetIntArrayElements(javaArray, 0);
int length = Env->GetArrayLength(javaArray);
for (int i = 0; i < length; i++)
{
numArray.Add((int)javaNum[i]);
}
return numArray;
}
// jlongArray to TArray<long>
TArray<long> JavaConvert::ConvertToLongArray(jlongArray javaArray)
{
TArray<long> longArray;
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jlong* javaLong = Env->GetLongArrayElements(javaArray, 0);
int length = Env->GetArrayLength(javaArray);
for (int i = 0; i < length; i++)
{
longArray.Add((long)javaLong[i]);
}
return longArray;
}
// jobjectArray to TArray<FString>
TArray<FString> JavaConvert::ConvertToStringArray(jobjectArray javaStringArray)
{
TArray<FString> stringArray;
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
int length = Env->GetArrayLength(javaStringArray);
for (int i = 0; i < length; i++)
{
jstring javaString = static_cast<jstring>(Env->GetObjectArrayElement(javaStringArray, i));
stringArray.Add(JavaConvert::FromJavaFString(javaString));
}
return stringArray;
}
// long to jlong
jlong JavaConvert::GetJavaLong(long l)
{
jlong jl = static_cast<jlong>(l);
return jl;
}
// FString to jstring
jstring JavaConvert::GetJavaString(FString string)
{
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
jstring local = JEnv->NewStringUTF(TCHAR_TO_UTF8(*string));
jstring result = (jstring)JEnv->NewGlobalRef(local);
JEnv->DeleteLocalRef(local);
return result;
}
// string to jstring
jstring JavaConvert::GetJavaString(string str)
{
FString string = str.c_str();
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
jstring local = JEnv->NewStringUTF(TCHAR_TO_UTF8(*string));
jstring result = (jstring)JEnv->NewGlobalRef(local);
JEnv->DeleteLocalRef(local);
return result;
}
// const char* to jstring
jstring JavaConvert::GetJavaString(const char* str)
{
string sstr = str;
FString string = sstr.c_str();
JNIEnv* JEnv = AndroidJavaEnv::GetJavaEnv();
jstring local = JEnv->NewStringUTF(TCHAR_TO_UTF8(*string));
jstring result = (jstring)JEnv->NewGlobalRef(local);
JEnv->DeleteLocalRef(local);
return result;
}
// jstring to FString
FString JavaConvert::FromJavaFString(jstring javaString)
{
JNIEnv* Env = AndroidJavaEnv::GetJavaEnv();
const char* UTFString = Env->GetStringUTFChars(javaString, nullptr);
FString Result(UTF8_TO_TCHAR(UTFString));
Env->ReleaseStringUTFChars(javaString, UTFString);
Env->DeleteLocalRef(javaString);
return Result;
}
// jstring to string
string JavaConvert::FromJavaString(jstring javaString)
{
JNIEnv* Env = AndroidJavaEnv::GetJavaEnv();
const char* UTFString = Env->GetStringUTFChars(javaString, nullptr);
FString Result(UTF8_TO_TCHAR(UTFString));
Env->ReleaseStringUTFChars(javaString, UTFString);
Env->DeleteLocalRef(javaString);
return string(TCHAR_TO_UTF8(*Result));
}
#pragma once
#include <Android/AndroidJNI.h>
#include <Android/AndroidApplication.h>
#include <Android/AndroidJava.h>
#include <iostream>
#include <string>
using namespace std;
class JavaConvert
{
public:
//======= Functions for converting to Java types ==================
// TArray<FString> to jobjectArray
static jobjectArray ConvertToJStringArray(const TArray<FString>& stringArray);
// TArray<bool> to jbooleanArray
static jbooleanArray ConvertToJBooleanArray(const TArray<bool>& boolArray);
// TArray<int> to jintArray
static jintArray ConvertToJIntArray(const TArray<int>& intArray);
// TArray<unsigned char> to jbyteArray
static jbyteArray ConvertToJByteArray(const TArray<uint8>& byteArray);
// TArray<long> to jlongArray
static jlongArray ConvertToJLongArray(const TArray<long>& longArray);
// TArray<float> to jfloatArray
static jfloatArray ConvertToJFloatArray(const TArray<float>& floatArray);
// jbyteArray to TArray<unsigned char>
static TArray<uint8> ConvertToByteArray(jbyteArray javaArray);
// jfloatArray to TArray<float>
static TArray<float> ConvertToFloatArray(jfloatArray javaArray);
// jfloatArray to TArray<int>
static TArray<int> ConvertToIntArray(jintArray javaArray);
// jlongArray to TArray<long>
static TArray<long> ConvertToLongArray(jlongArray javaArray);
// jobjectArray to TArray<FString>
static TArray<FString> ConvertToStringArray(jobjectArray javaStringArray);
// long to jlong
static jlong GetJavaLong(long l);
// FString to jstring
static jstring GetJavaString(FString string);
// string to jstring
static jstring GetJavaString(string str);
// const char* to jstring
static jstring GetJavaString(const char* str);
// jstring to FString
static FString FromJavaFString(jstring javaString);
// jstring to string
static string FromJavaString(jstring javaString);
};
#include "HuaweiIAP.h"
using namespace std;
#if PLATFORM_ANDROID
#include "Android/Utils/AndroidUtils.h"
#include "Android/AndroidJNI.h"
#endif
#include <set>
#pragma region GetIapClient
static std::set<UHmsIap*> s_hmsIaps;
UHmsIap::UHmsIap(){}
UHmsIap::~UHmsIap()
{
std::set<UHmsIap*>::iterator it = s_hmsIaps.find(this);
if (it != s_hmsIaps.end())
{
s_hmsIaps.erase(it);
}
}
UHmsIap* UHmsIap::GetIapClient()
{
UHmsIap* BPNode = NewObject<UHmsIap>();
s_hmsIaps.insert(BPNode);
return BPNode;
}
#if PLATFORM_ANDROID
static void ReqGetIapClient()
{
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
static jmethodID IsEnvReadyMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_IsEnvReady", "()V", false);
if (IsEnvReadyMethod == nullptr)
{
UE_LOG(LogTemp, Log, TEXT("AndroidThunkJava_IsEnvReady not found"));
return;
}
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, IsEnvReadyMethod);
}
}
__attribute__((visibility("default"))) extern "C" void Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativeGetIapClientResult(JNIEnv* jenv, jobject thiz, jboolean success)
{
DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativeGetIapClientResult"), STAT_FSimpleDelegateGraphTask_Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativeGetIapClientResult, STATGROUP_TaskGraphTasks);
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
FSimpleDelegateGraphTask::FDelegate::CreateLambda([=]()
{
if ((bool)success)
{
UHmsIap* hmsIap = NewObject<UHmsIap>();
for (std::set<UHmsIap*>::iterator it = s_hmsIaps.begin(); it != s_hmsIaps.end(); it++)
{
UE_LOG(LogTemp, Log, TEXT("std::set<UHmsIap*>::iterator it"));
(*it)->OnComplete.Broadcast(true);
}
}
else
{
for (std::set<UHmsIap*>::iterator it = s_hmsIaps.begin(); it != s_hmsIaps.end(); it++)
{
(*it)->OnComplete.Broadcast(false);
}
}
s_hmsIaps.clear();
}),
GET_STATID(STAT_FSimpleDelegateGraphTask_Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativeGetIapClientResult),
nullptr,
ENamedThreads::GameThread
);
}
#endif
void UHmsIap::Activate()
{
#if PLATFORM_ANDROID
ReqGetIapClient();
#endif
}
#pragma endregion
#pragma region QueryProducts
static std::set<UHmsQueryProducts*> s_hmsQueryProductses;
UHmsQueryProducts::UHmsQueryProducts(){}
UHmsQueryProducts::~UHmsQueryProducts()
{
std::set<UHmsQueryProducts*>::iterator it = s_hmsQueryProductses.find(this);
if (it != s_hmsQueryProductses.end())
{
s_hmsQueryProductses.erase(it);
}
}
UHmsQueryProducts* UHmsQueryProducts::QueryProducts()
{
UHmsQueryProducts* BPNode = NewObject<UHmsQueryProducts>();
s_hmsQueryProductses.insert(BPNode);
return BPNode;
}
#if PLATFORM_ANDROID
static void ReqQueryProducts()
{
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
static jmethodID QueryProductsMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_QueryProducts", "()V", false);
if (QueryProductsMethod)
{
UE_LOG(LogTemp, Log, TEXT("Find AndroidThunkJava_QueryProducts"));
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, QueryProductsMethod);
}
}
}
__attribute__((visibility("default"))) extern "C" void Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativeQueryProductsResult(JNIEnv* jenv, jobject thiz, jboolean success)
{
DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativeQueryProductsResult"), STAT_FSimpleDelegateGraphTask_Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativeQueryProductsResult, STATGROUP_TaskGraphTasks);
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
FSimpleDelegateGraphTask::FDelegate::CreateLambda([=]()
{
if ((bool)success)
{
UHmsQueryProducts* hmsQueryProducts = NewObject<UHmsQueryProducts>();
for (std::set<UHmsQueryProducts*>::iterator it = s_hmsQueryProductses.begin(); it != s_hmsQueryProductses.end(); it++)
{
(*it)->OnComplete.Broadcast(true);
}
}
else
{
for (std::set<UHmsQueryProducts*>::iterator it = s_hmsQueryProductses.begin(); it != s_hmsQueryProductses.end(); it++)
{
(*it)->OnComplete.Broadcast(false);
}
}
s_hmsQueryProductses.clear();
}),
GET_STATID(STAT_FSimpleDelegateGraphTask_Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativeQueryProductsResult),
nullptr,
ENamedThreads::GameThread
);
}
#endif
void UHmsQueryProducts::Activate()
{
#if PLATFORM_ANDROID
ReqQueryProducts();
#endif
}
#pragma endregion
#pragma region Payment
static std::set<UHmsPayment*> s_hmsPayments;
UHmsPayment::UHmsPayment(){}
UHmsPayment::~UHmsPayment()
{
std::set<UHmsPayment*>::iterator it = s_hmsPayments.find(this);
if (it != s_hmsPayments.end())
{
s_hmsPayments.erase(it);
}
}
UHmsPayment* UHmsPayment::Payment(const FHmsIapProductRequest& ProductRequest)
{
UHmsPayment* BPNode = NewObject<UHmsPayment>();
BPNode->ProductRequest = ProductRequest;
s_hmsPayments.insert(BPNode);
return BPNode;
}
#if PLATFORM_ANDROID
static void ReqPayment(const FString& ProductId)
{
UE_LOG(LogTemp, Log, TEXT("%s"), *ProductId);
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
UE_LOG(LogTemp, Log, TEXT("Find JNI"));
static jmethodID PaymentMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Payment", "(Ljava/lang/String;)V", false);
if (PaymentMethod == nullptr)
{
UE_LOG(LogTemp, Log, TEXT("AndroidThunkJava_Payment not found"));
return;
}
UE_LOG(LogTemp, Log, TEXT("ToString ProductId"));
// auto Argument = FJavaHelper::ToJavaString(Env, ProductId);
jstring jProductId = Env->NewStringUTF(TCHAR_TO_UTF8(*ProductId));
UE_LOG(LogTemp, Log, TEXT("CallVoidMethod"));
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, PaymentMethod, jProductId);
}
}
__attribute__((visibility("default"))) extern "C" void Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativePaymentResult(JNIEnv* jenv, jobject thiz, jstring purchaseToken, jstring productId)
{
UE_LOG(LogTemp, Log, TEXT("nativePaymentResult"));
const char* charsPurchaseToken = jenv->GetStringUTFChars(purchaseToken, 0);
const char* charsProductId = jenv->GetStringUTFChars(productId, 0);
FString strPurchaseToken = FString(UTF8_TO_TCHAR(charsPurchaseToken));
FString strProductId = FString(UTF8_TO_TCHAR(charsProductId));
DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativePaymentResult"), STAT_FSimpleDelegateGraphTask_Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativePaymentResult, STATGROUP_TaskGraphTasks);
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
FSimpleDelegateGraphTask::FDelegate::CreateLambda([=]()
{
// Success
if (strPurchaseToken.Len() > 0 && strProductId.Len() > 0)
{
UHmsPayment* hmsPayment = NewObject<UHmsPayment>();
for (std::set<UHmsPayment*>::iterator it = s_hmsPayments.begin(); it != s_hmsPayments.end(); it++)
{
(*it)->OnSuccess.Broadcast(strPurchaseToken, strProductId);
}
}
else
{
for (std::set<UHmsPayment*>::iterator it = s_hmsPayments.begin(); it != s_hmsPayments.end(); it++)
{
(*it)->OnFailure.Broadcast(strPurchaseToken, strProductId);
}
}
s_hmsPayments.clear();
}),
GET_STATID(STAT_FSimpleDelegateGraphTask_Java_com_Plugins_HuaweiSDK_activity_EntryActivity_nativePaymentResult),
nullptr,
ENamedThreads::GameThread
);
}
#endif
void UHmsPayment::Activate()
{
#if PLATFORM_ANDROID
ReqPayment(ProductRequest.ProductId);
#endif
}
#pragma endregion
\ No newline at end of file
// Copyright Epic Games, Inc. All Rights Reserved.
#include "HuaweiSDK.h"
#define LOCTEXT_NAMESPACE "FHuaweiSDKModule"
#ifdef __ANDROID__
// perform startup operations for Android
//extern int SetupJNI_HuaweiSDK();
#endif
void FHuaweiSDKModule::StartupModule()
{
#ifdef __ANDROID__
//SetupJNI_HuaweiSDK();
#endif
}
void FHuaweiSDKModule::ShutdownModule()
{
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FHuaweiSDKModule, HuaweiSDK)
\ No newline at end of file
#include "MobileNativeCode.h"
#define LOCTEXT_NAMESPACE "FMobileNativeCodeModule"
void FMobileNativeCodeModule::StartupModule()
{
// This code will be executed after loading your module into memory; the exact time is specified in the .plugin file for each module.
}
void FMobileNativeCodeModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
}
#undef LOCTEXT_NAMESPACE
\ No newline at end of file
#include "MobileNativeCodeBlueprint.h"
using namespace std;
#if PLATFORM_ANDROID
#include "Android/Utils/AndroidUtils.h"
#endif
FString UMobileNativeCodeBlueprint::HelloWorld(FString MyStr)
{
#if PLATFORM_ANDROID
MyStr = AndroidUtils::CallJavaCode<FString>(
"com/Plugins/HuaweiSDK/activity/Test",
"Test",
"",
false,
MyStr
);
#endif
UE_LOG(LogTemp, Log, TEXT("%s"), *MyStr);
return MyStr;
}
void UMobileNativeCodeBlueprint::GetIapClient()
{
#if PLATFORM_ANDROID
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
UE_LOG(LogTemp, Log, TEXT("Find Jni"));
static jmethodID GetIapClientMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Iap_GetIapClient", "()V", false);
if (GetIapClientMethod)
{
UE_LOG(LogTemp, Log, TEXT("Find AndroidThunkJava_Iap_GetIapClient"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("not found AndroidThunkJava_Iap_GetIapClient"));
}
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, GetIapClientMethod);
UE_LOG(LogTemp, Log, TEXT("FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, GetIapClientMethod)"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("JNI Error"));
}
#endif
}
void UMobileNativeCodeBlueprint::Payment(int index)
{
#if PLATFORM_ANDROID
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
UE_LOG(LogTemp, Log, TEXT("Find Jni"));
static jmethodID PaymentMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Payment", "()V", false);
if (PaymentMethod)
{
UE_LOG(LogTemp, Log, TEXT("Find AndroidThunkJava_CreateHuaweiIap"));
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, PaymentMethod);
}
}
#endif
}
void UMobileNativeCodeBlueprint::IsEnvReady()
{
#if PLATFORM_ANDROID
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
UE_LOG(LogTemp, Log, TEXT("Find JNI"));
static jmethodID IsEnvReadyMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_IsEnvReady", "()V", false);
if (IsEnvReadyMethod)
{
UE_LOG(LogTemp, Log, TEXT("Find AndroidThunkJava_IsEnvReady"));
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, IsEnvReadyMethod);
UE_LOG(LogTemp, Log, TEXT("FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, IsEnvReadyMethod)"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("not found AndroidThunkJava_IsEnvReady"));
}
}
#endif
}
void UMobileNativeCodeBlueprint::QueryProducts()
{
#if PLATFORM_ANDROID
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
static jmethodID QueryProductsMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_QueryProducts", "()V", false);
if (QueryProductsMethod)
{
UE_LOG(LogTemp, Log, TEXT("Find AndroidThunkJava_QueryProducts"));
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, QueryProductsMethod);
}
}
#endif
}
// #pragma once
//
// #ifdef __ANDROID__
//
// #include "CoreMinimal.h"
// #include "Android/AndroidJNI.h"
// #include "Android/AndroidApplication.h"
//
// #include <string.h>
// #include <jni.h>
// #include <stdio.h>
//
// // Bind JNI methods for the export HuaweiIAP function
// extern int SetupJNI_HuaweiSDK_IapClient();
//
// // Called during module startup for Android
// int SetupJNI_HuaweiSDK()
// {
// JNIEnv* env = FAndroidApplication::GetJavaEnv();
// if (!env) return JNI_ERR;
//
// JNIEnv* ENV = env;
//
// SetupJNI_HuaweiSDK_IapClient();
//
// return JNI_OK;
// }
//
// #endif
\ No newline at end of file
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "HuaweiIAP.generated.h"
#pragma region HuaweiIap Struct
USTRUCT(BlueprintType)
struct FHmsIapProductRequest
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadWrite, Category=ProductInfo)
FString ProductId;
};
USTRUCT(BlueprintType)
struct FHmsIapProductInfo
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadWrite, Category=ProductInfo)
FString ProductId;
};
USTRUCT(BlueprintType)
struct FHmsIapReceiptInfo
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadWrite, Category=ProductInfo)
FString ProductId;
UPROPERTY(BlueprintReadWrite, Category=ProductInfo)
FString PurchaseToken;
};
#pragma endregion
#pragma region GetIapClient
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FGetIapClient, bool, IsSuccess);
UCLASS(Category = "Huawei IAP", meta = (DisplayName = "Huawei IAP"))
class HUAWEISDK_API UHmsIap : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UHmsIap();
~UHmsIap();
UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly="true"), Category="HuaweiIap")
static UHmsIap* GetIapClient();
virtual void Activate() override;
UPROPERTY(BlueprintAssignable)
FGetIapClient OnComplete;
};
#pragma endregion
#pragma region QueryProducts
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FQueryProducts, bool, IsSuccess);
UCLASS()
class HUAWEISDK_API UHmsQueryProducts : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UHmsQueryProducts();
~UHmsQueryProducts();
UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly="true"), Category="HuaweiIap")
static UHmsQueryProducts* QueryProducts();
virtual void Activate() override;
UPROPERTY(BlueprintAssignable)
FQueryProducts OnComplete;
};
#pragma endregion
#pragma region Payment
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FPaymentResult, FString, PurchaseToken, FString, ProductId);
UCLASS(Category = "Huawei IAP", meta=(DisplayName="Huawei IAP"))
class HUAWEISDK_API UHmsPayment : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UHmsPayment();
~UHmsPayment();
UFUNCTION(BlueprintCallable, meta=(BlueprintINternalUseOnly="true"), Category="HuaweiIap")
static UHmsPayment* Payment(const FHmsIapProductRequest& ProductRequest);
virtual void Activate() override;
UPROPERTY(BlueprintAssignable)
FPaymentResult OnSuccess;
UPROPERTY(BlueprintAssignable)
FPaymentResult OnFailure;
private:
FHmsIapProductRequest ProductRequest;
};
#pragma endregion
\ No newline at end of file
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FHuaweiSDKModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
#pragma once
#include "Modules/ModuleManager.h"
class FMobileNativeCodeModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
#pragma once
#include <Kismet/BlueprintFunctionLibrary.h>
#include <Async/Async.h>
#include <Engine.h>
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "MobileNativeCodeBlueprint.generated.h"
UCLASS()
class HUAWEISDK_API UMobileNativeCodeBlueprint : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UMobileNativeCodeBlueprint(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {};
UFUNCTION(BlueprintCallable, Category = "MobileNativeCode Category")
static FString HelloWorld(FString MyStr = "Hello World");
UFUNCTION(BlueprintCallable, Category = "HuaweiSDK Category")
static void GetIapClient();
UFUNCTION(BlueprintCallable, Category = "HuaweiSDK Category")
static void Payment(int index);
UFUNCTION(BlueprintCallable, Category = "HuaweiSDK Category")
static void IsEnvReady();
UFUNCTION(BlueprintCallable, Category = "HuaweiSDK Category")
static void QueryProducts();
};
\ No newline at end of file
{
"agcgw_all":{
"CN":"connect-drcn.hispace.hicloud.com",
"CN_back":"connect-drcn.dbankcloud.cn",
"DE":"connect-dre.hispace.hicloud.com",
"DE_back":"connect-dre.dbankcloud.cn",
"RU":"connect-drru.hispace.hicloud.com",
"RU_back":"connect-drru.dbankcloud.cn",
"SG":"connect-dra.hispace.hicloud.com",
"SG_back":"connect-dra.dbankcloud.cn"
},
"client":{
"cp_id":"5190034000026133052",
"product_id":"736430079245931467",
"client_id":"691785785543771008",
"client_secret":"422FB2434009A0996774EFB08AEEAC46DC604D0B6ADB941DF153F193D1295B93",
"project_id":"736430079245931467",
"app_id":"104587347",
"api_key":"CwEAAAAAD2viQSwipCEmqSybOd7pU/K6WjgPBkavH8Urp8sq8JQk2RCgRMoAqSXQ/rL8qEnV0WBkUdmxsncTOVoKY8OynO0KLQY=",
"package_name":"com.tdf.rmvw2021.huawei"
},
"oauth_client":{
"client_id":"104587347",
"client_type":1
},
"app_info":{
"app_id":"104587347",
"package_name":"com.tdf.rmvw2021.huawei"
},
"configuration_version":"3.0",
"appInfos":[
{
"package_name":"com.tdf.rmvw2021.huawei",
"client":{
"app_id":"104587347"
},
"app_info":{
"package_name":"com.tdf.rmvw2021.huawei",
"app_id":"104587347"
},
"oauth_client":{
"client_type":1,
"client_id":"104587347"
}
}
]
}
\ No newline at end of file
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
using System.Collections.Generic;
public class HuaweiTarget : TargetRules
{
public HuaweiTarget( TargetInfo Target) : base(Target)
{
Type = TargetType.Game;
DefaultBuildSettings = BuildSettingsVersion.V2;
ExtraModuleNames.AddRange( new string[] { "Huawei" } );
}
}
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class Huawei : ModuleRules
{
public Huawei(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Json", "JsonUtilities", "Http" });
PrivateDependencyModuleNames.AddRange(new string[] { });
// Uncomment if you are using Slate UI
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
// Uncomment if you are using online features
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
}
}
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Huawei.h"
#include "Modules/ModuleManager.h"
IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, Huawei, "Huawei" );
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
// Copyright Epic Games, Inc. All Rights Reserved.
#include "HuaweiGameModeBase.h"
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "HuaweiGameModeBase.generated.h"
/**
*
*/
UCLASS()
class HUAWEI_API AHuaweiGameModeBase : public AGameModeBase
{
GENERATED_BODY()
};
#include "Protocol.h"
// #include "Interfaces/IHttpResponse.h"
#include "Http.h"
#pragma region Protocol/PurchaseHmsAPI
UPurchaseHmsAPI* UPurchaseHmsAPI::PurchaseHms(const FString& PurchaseToken, const FString& ProductId)
{
UPurchaseHmsAPI* BPNode = NewObject<UPurchaseHmsAPI>();
BPNode->PurchaseToken = PurchaseToken;
BPNode->ProductId = ProductId;
return BPNode;
}
void UPurchaseHmsAPI::Activate()
{
TSharedRef<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest();
HttpRequest->SetURL(FString::Printf(TEXT("http://59.10.234.195:8080/huawei-test")));
HttpRequest->SetHeader(TEXT("content-type"), TEXT("application/json"));
// HttpRequest->SetHeader(TEXT("authorization"), *URMProtocolFunctionLibrary::GetAccessToken());
HttpRequest->SetVerb(TEXT("POST"));
TSharedPtr<FJsonObject> _payloadJson = MakeShareable(new FJsonObject());
_payloadJson->SetStringField("purchaseToken", *PurchaseToken);
_payloadJson->SetStringField("productId", *ProductId);
FString _payload;
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&_payload);
FJsonSerializer::Serialize(_payloadJson.ToSharedRef(), Writer);
HttpRequest->SetContentAsString(_payload);
if (HttpRequest->ProcessRequest())
{
HttpRequest->OnProcessRequestComplete().BindUObject(this, &UPurchaseHmsAPI::OnResponse);
UE_LOG(LogTemp, Log, TEXT("UPurchaseHmsAPI : %s : %s"), *HttpRequest->GetURL(), *_payload);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("UPurchaseHmsAPI - cannot process request"));
}
}
void UPurchaseHmsAPI::OnResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool WasSuccessful)
{
if (!WasSuccessful || Response->GetResponseCode() != 200)
{
FString Msg = FString::Printf(TEXT("Error processing request.\n%s\n%s"), *Response->GetContentAsString(), *Response->GetURL());
UE_LOG(LogTemp, Log, TEXT("%s"), *Msg);
Finished.Broadcast(Response->GetResponseCode(), false, Msg);
return;
}
UE_LOG(LogTemp, Log, TEXT("OnResponse : %s"), *Response->GetContentAsString());
TSharedPtr<FJsonObject> res;
TSharedRef<TJsonReader<>> reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
if (FJsonSerializer::Deserialize(reader, res))
{
int resultCode = res->GetIntegerField("resultCode");
if (resultCode == 200)
{
Finished.Broadcast(resultCode, true, TEXT(""));
}
else
{
Finished.Broadcast(resultCode, false, res->GetStringField("resultMessage"));
}
}
}
#pragma endregion
\ No newline at end of file
#pragma once
#include "CoreMinimal.h"
#include "HttpModule.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Protocol.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FPurchaseHmsFinishedPin, int32, ResultCode, bool, success, FString, ErrMessage);
UCLASS()
class HUAWEI_API UPurchaseHmsAPI : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UPurchaseHmsAPI(){}
UPROPERTY(BlueprintAssignable, Category="Protocol")
FPurchaseHmsFinishedPin Finished;
private:
UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly="true"), Category="Protocol")
static UPurchaseHmsAPI* PurchaseHms(const FString& PurchaseToken, const FString& ProductId);
virtual void Activate() override;
void OnResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool WasSuccessful);
FString PurchaseToken;
FString ProductId;
};
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
using System.Collections.Generic;
public class HuaweiEditorTarget : TargetRules
{
public HuaweiEditorTarget( TargetInfo Target) : base(Target)
{
Type = TargetType.Editor;
DefaultBuildSettings = BuildSettingsVersion.V2;
ExtraModuleNames.AddRange( new string[] { "Huawei" } );
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment