From 92e4a6c7df77c29e99b873f98a3773a38c85cd85 Mon Sep 17 00:00:00 2001 From: Ivan Murashka Date: Thu, 25 Jun 2026 19:32:28 +0200 Subject: [PATCH 1/2] feat: implement UMP consent service for Android and iOS --- src/Editor/UmpKitDependencies.xml | 9 + src/Editor/UmpKitDependencies.xml.meta | 7 + src/Runtime/Appegy.Ump.asmdef | 4 +- src/Runtime/IUmpConsentService.cs | 18 ++ src/Runtime/IUmpConsentService.cs.meta | 2 + src/Runtime/Plugins.meta | 8 + src/Runtime/Plugins/Android.meta | 8 + .../Plugins/Android/UmpKitConsent.java | 164 +++++++++++++++++ .../Plugins/Android/UmpKitConsent.java.meta | 2 + src/Runtime/Plugins/iOS.meta | 8 + src/Runtime/Plugins/iOS/UmpKitConsent.m | 119 ++++++++++++ src/Runtime/Plugins/iOS/UmpKitConsent.m.meta | 2 + src/Runtime/UmpCallbackReceiver.cs | 18 ++ src/Runtime/UmpCallbackReceiver.cs.meta | 2 + src/Runtime/UmpConsentService.cs | 170 ++++++++++++++++++ src/Runtime/UmpConsentService.cs.meta | 2 + src/Runtime/UmpTypes.cs | 64 +++++++ src/Runtime/UmpTypes.cs.meta | 2 + 18 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 src/Editor/UmpKitDependencies.xml create mode 100644 src/Editor/UmpKitDependencies.xml.meta create mode 100644 src/Runtime/IUmpConsentService.cs create mode 100644 src/Runtime/IUmpConsentService.cs.meta create mode 100644 src/Runtime/Plugins.meta create mode 100644 src/Runtime/Plugins/Android.meta create mode 100644 src/Runtime/Plugins/Android/UmpKitConsent.java create mode 100644 src/Runtime/Plugins/Android/UmpKitConsent.java.meta create mode 100644 src/Runtime/Plugins/iOS.meta create mode 100644 src/Runtime/Plugins/iOS/UmpKitConsent.m create mode 100644 src/Runtime/Plugins/iOS/UmpKitConsent.m.meta create mode 100644 src/Runtime/UmpCallbackReceiver.cs create mode 100644 src/Runtime/UmpCallbackReceiver.cs.meta create mode 100644 src/Runtime/UmpConsentService.cs create mode 100644 src/Runtime/UmpConsentService.cs.meta create mode 100644 src/Runtime/UmpTypes.cs create mode 100644 src/Runtime/UmpTypes.cs.meta diff --git a/src/Editor/UmpKitDependencies.xml b/src/Editor/UmpKitDependencies.xml new file mode 100644 index 0000000..d97bd2a --- /dev/null +++ b/src/Editor/UmpKitDependencies.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/Editor/UmpKitDependencies.xml.meta b/src/Editor/UmpKitDependencies.xml.meta new file mode 100644 index 0000000..992d1e9 --- /dev/null +++ b/src/Editor/UmpKitDependencies.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4f9780273dd3046ea836173f85ca5e08 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Runtime/Appegy.Ump.asmdef b/src/Runtime/Appegy.Ump.asmdef index 25b5f35..e6fdd41 100644 --- a/src/Runtime/Appegy.Ump.asmdef +++ b/src/Runtime/Appegy.Ump.asmdef @@ -1,7 +1,9 @@ { "name": "Appegy.Ump", "rootNamespace": "Appegy.Ump", - "references": [], + "references": [ + "UniTask" + ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, diff --git a/src/Runtime/IUmpConsentService.cs b/src/Runtime/IUmpConsentService.cs new file mode 100644 index 0000000..cffc382 --- /dev/null +++ b/src/Runtime/IUmpConsentService.cs @@ -0,0 +1,18 @@ +using System.Threading; +using Cysharp.Threading.Tasks; + +namespace Appegy.Ump +{ + public interface IUmpConsentService + { + bool IsPrivacyOptionsRequired { get; } + + UniTask InitializeAsync(UmpInitializeParameters parameters, CancellationToken ct); + + UniTask ShowFormIfRequiredAsync(CancellationToken ct); + + UniTask ShowPrivacyOptionsFormAsync(CancellationToken ct); + + UniTask ResetConsentAsync(CancellationToken ct); + } +} diff --git a/src/Runtime/IUmpConsentService.cs.meta b/src/Runtime/IUmpConsentService.cs.meta new file mode 100644 index 0000000..75fbebb --- /dev/null +++ b/src/Runtime/IUmpConsentService.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 962a311bd3fba565f89ed4e22f707638 \ No newline at end of file diff --git a/src/Runtime/Plugins.meta b/src/Runtime/Plugins.meta new file mode 100644 index 0000000..a84c5c3 --- /dev/null +++ b/src/Runtime/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1dfb4fae9c1b6c2d8d8f2d6d4f4cc6d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Runtime/Plugins/Android.meta b/src/Runtime/Plugins/Android.meta new file mode 100644 index 0000000..ea26da7 --- /dev/null +++ b/src/Runtime/Plugins/Android.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c93ef962d348462599826334511b437f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Runtime/Plugins/Android/UmpKitConsent.java b/src/Runtime/Plugins/Android/UmpKitConsent.java new file mode 100644 index 0000000..8c9c349 --- /dev/null +++ b/src/Runtime/Plugins/Android/UmpKitConsent.java @@ -0,0 +1,164 @@ +package com.appegy.ump; + +import com.google.android.ump.ConsentDebugSettings; +import com.google.android.ump.ConsentInformation; +import com.google.android.ump.ConsentRequestParameters; +import com.google.android.ump.FormError; +import com.google.android.ump.UserMessagingPlatform; +import com.unity3d.player.UnityPlayer; + +import android.app.Activity; + +public final class UmpKitConsent +{ + private static final String GAME_OBJECT = "UmpKit"; + private static final String METHOD = "OnUmpMessage"; + + private static ConsentInformation consentInformation; + private static boolean formAvailable = false; + + private UmpKitConsent() {} + + private static Activity activity() + { + return UnityPlayer.currentActivity; + } + + private static int status() + { + try + { + return consentInformation == null ? 0 : consentInformation.getConsentStatus(); + } + catch (Exception e) + { + return 0; + } + } + + private static void send(String op, int status, int error, int nativeCode, String message) + { + if (message == null) + { + message = ""; + } + String payload = op + "|" + status + "|" + error + "|" + nativeCode + "|" + message; + UnityPlayer.UnitySendMessage(GAME_OBJECT, METHOD, payload); + } + + public static void Initialize(final int debugGeography, final String testDevice) + { + activity().runOnUiThread(() -> doInitialize(debugGeography, testDevice)); + } + + private static void doInitialize(int debugGeography, String testDevice) + { + ConsentRequestParameters.Builder builder = new ConsentRequestParameters.Builder() + .setTagForUnderAgeOfConsent(false); + + if (debugGeography > 0 && testDevice != null && testDevice.length() > 0) + { + ConsentDebugSettings debug = new ConsentDebugSettings.Builder(activity()) + .setDebugGeography(debugGeography) + .addTestDeviceHashedId(testDevice) + .build(); + builder.setConsentDebugSettings(debug); + } + + ConsentRequestParameters params = builder.build(); + consentInformation = UserMessagingPlatform.getConsentInformation(activity()); + consentInformation.requestConsentInfoUpdate( + activity(), + params, + () -> + { + formAvailable = consentInformation.isConsentFormAvailable(); + send("init", status(), 0, 0, ""); + }, + formError -> + { + send("init", status(), 1, formError.getErrorCode(), formError.getMessage()); + }); + } + + public static void ShowFormIfRequired() + { + activity().runOnUiThread(UmpKitConsent::doShowFormIfRequired); + } + + private static void doShowFormIfRequired() + { + if (consentInformation == null) + { + send("show", 0, 4, 0, "not initialized"); + return; + } + + if (consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.REQUIRED && !formAvailable) + { + send("show", status(), 2, 0, "form not available"); + return; + } + + UserMessagingPlatform.loadAndShowConsentFormIfRequired( + activity(), + formError -> + { + if (formError != null) + { + send("show", status(), 3, formError.getErrorCode(), formError.getMessage()); + } + else + { + send("show", status(), 0, 0, ""); + } + }); + } + + public static void ShowPrivacyOptionsForm() + { + activity().runOnUiThread(UmpKitConsent::doShowPrivacyOptions); + } + + private static void doShowPrivacyOptions() + { + if (consentInformation == null) + { + send("privacy", 0, 4, 0, "not initialized"); + return; + } + + UserMessagingPlatform.showPrivacyOptionsForm( + activity(), + formError -> + { + if (formError != null) + { + send("privacy", status(), 3, formError.getErrorCode(), formError.getMessage()); + } + else + { + send("privacy", status(), 0, 0, ""); + } + }); + } + + public static void ResetConsent() + { + if (consentInformation != null) + { + consentInformation.reset(); + } + formAvailable = false; + } + + public static boolean IsPrivacyOptionsRequired() + { + if (consentInformation == null) + { + return false; + } + return consentInformation.getPrivacyOptionsRequirementStatus() + == ConsentInformation.PrivacyOptionsRequirementStatus.REQUIRED; + } +} diff --git a/src/Runtime/Plugins/Android/UmpKitConsent.java.meta b/src/Runtime/Plugins/Android/UmpKitConsent.java.meta new file mode 100644 index 0000000..bcd5edd --- /dev/null +++ b/src/Runtime/Plugins/Android/UmpKitConsent.java.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c6f2e6e20f30d58528e99daa55e2738f \ No newline at end of file diff --git a/src/Runtime/Plugins/iOS.meta b/src/Runtime/Plugins/iOS.meta new file mode 100644 index 0000000..3bbbe2b --- /dev/null +++ b/src/Runtime/Plugins/iOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 07b6d77aceebf87119b10c17a76d4c03 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Runtime/Plugins/iOS/UmpKitConsent.m b/src/Runtime/Plugins/iOS/UmpKitConsent.m new file mode 100644 index 0000000..d34c361 --- /dev/null +++ b/src/Runtime/Plugins/iOS/UmpKitConsent.m @@ -0,0 +1,119 @@ +#import +#import "UnityInterface.h" + +extern void UnitySendMessage(const char *, const char *, const char *); + +static const char *const kGameObject = "UmpKit"; +static const char *const kMethod = "OnUmpMessage"; + +static int UmpCanonicalStatus(UMPConsentStatus status) +{ + switch (status) + { + case UMPConsentStatusNotRequired: return 1; + case UMPConsentStatusRequired: return 2; + case UMPConsentStatusObtained: return 3; + default: return 0; + } +} + +static int UmpCurrentStatus(void) +{ + return UmpCanonicalStatus(UMPConsentInformation.sharedInstance.consentStatus); +} + +static void UmpSend(const char *op, int status, int error, int nativeCode, NSString *message) +{ + if (message == nil) + { + message = @""; + } + NSString *payload = [NSString stringWithFormat:@"%s|%d|%d|%d|%@", op, status, error, nativeCode, message]; + UnitySendMessage(kGameObject, kMethod, [payload UTF8String]); +} + +void _UmpInitialize(int debugGeography, const char *testDevice) +{ + UMPRequestParameters *parameters = [[UMPRequestParameters alloc] init]; + parameters.tagForUnderAgeOfConsent = NO; + + NSString *device = testDevice != NULL ? [NSString stringWithUTF8String:testDevice] : @""; + if (debugGeography > 0 && device.length > 0) + { + UMPDebugSettings *debug = [[UMPDebugSettings alloc] init]; + debug.geography = (UMPDebugGeography)debugGeography; + debug.testDeviceIdentifiers = @[ device ]; + parameters.debugSettings = debug; + } + + [UMPConsentInformation.sharedInstance + requestConsentInfoUpdateWithParameters:parameters + completionHandler:^(NSError *_Nullable error) + { + if (error) + { + UmpSend("init", UmpCurrentStatus(), 1, (int)error.code, error.localizedDescription); + } + else + { + UmpSend("init", UmpCurrentStatus(), 0, 0, @""); + } + }]; +} + +void _UmpShowFormIfRequired(void) +{ + dispatch_async(dispatch_get_main_queue(), ^{ + UIViewController *controller = UnityGetGLViewController(); + + if (UMPConsentInformation.sharedInstance.consentStatus == UMPConsentStatusRequired + && UMPConsentInformation.sharedInstance.formStatus != UMPFormStatusAvailable) + { + UmpSend("show", UmpCurrentStatus(), 2, 0, @"form not available"); + return; + } + + [UMPConsentForm loadAndPresentIfRequiredFromViewController:controller + completionHandler:^(NSError *_Nullable error) + { + if (error) + { + UmpSend("show", UmpCurrentStatus(), 3, (int)error.code, error.localizedDescription); + } + else + { + UmpSend("show", UmpCurrentStatus(), 0, 0, @""); + } + }]; + }); +} + +void _UmpShowPrivacyOptionsForm(void) +{ + dispatch_async(dispatch_get_main_queue(), ^{ + UIViewController *controller = UnityGetGLViewController(); + [UMPConsentForm presentPrivacyOptionsFormFromViewController:controller + completionHandler:^(NSError *_Nullable error) + { + if (error) + { + UmpSend("privacy", UmpCurrentStatus(), 3, (int)error.code, error.localizedDescription); + } + else + { + UmpSend("privacy", UmpCurrentStatus(), 0, 0, @""); + } + }]; + }); +} + +void _UmpResetConsent(void) +{ + [UMPConsentInformation.sharedInstance reset]; +} + +bool _UmpIsPrivacyOptionsRequired(void) +{ + return UMPConsentInformation.sharedInstance.privacyOptionsRequirementStatus + == UMPPrivacyOptionsRequirementStatusRequired; +} diff --git a/src/Runtime/Plugins/iOS/UmpKitConsent.m.meta b/src/Runtime/Plugins/iOS/UmpKitConsent.m.meta new file mode 100644 index 0000000..afb6abd --- /dev/null +++ b/src/Runtime/Plugins/iOS/UmpKitConsent.m.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9fd1eac7e54bcb61b8931d76d0440b17 \ No newline at end of file diff --git a/src/Runtime/UmpCallbackReceiver.cs b/src/Runtime/UmpCallbackReceiver.cs new file mode 100644 index 0000000..5460cee --- /dev/null +++ b/src/Runtime/UmpCallbackReceiver.cs @@ -0,0 +1,18 @@ +using System; +using UnityEngine; +using UnityEngine.Scripting; + +namespace Appegy.Ump +{ + [Preserve] + internal sealed class UmpCallbackReceiver : MonoBehaviour + { + public Action OnMessage; + + [Preserve] + public void OnUmpMessage(string payload) + { + OnMessage?.Invoke(payload); + } + } +} diff --git a/src/Runtime/UmpCallbackReceiver.cs.meta b/src/Runtime/UmpCallbackReceiver.cs.meta new file mode 100644 index 0000000..f5512cb --- /dev/null +++ b/src/Runtime/UmpCallbackReceiver.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 71eddfd72bb801e8a96e3e067a650839 \ No newline at end of file diff --git a/src/Runtime/UmpConsentService.cs b/src/Runtime/UmpConsentService.cs new file mode 100644 index 0000000..5a765f2 --- /dev/null +++ b/src/Runtime/UmpConsentService.cs @@ -0,0 +1,170 @@ +using System; +using System.Globalization; +using System.Threading; +using Cysharp.Threading.Tasks; +using UnityEngine; +#if UNITY_IOS && !UNITY_EDITOR +using System.Runtime.InteropServices; +#endif + +namespace Appegy.Ump +{ + public sealed class UmpConsentService : IUmpConsentService + { + private const string GameObjectName = "UmpKit"; + private const string AndroidClass = "com.appegy.ump.UmpKitConsent"; + + private UmpCallbackReceiver _receiver; + private UniTaskCompletionSource _pending; + +#if UNITY_IOS && !UNITY_EDITOR + [DllImport("__Internal")] private static extern void _UmpInitialize(int debugGeography, string testDevice); + [DllImport("__Internal")] private static extern void _UmpShowFormIfRequired(); + [DllImport("__Internal")] private static extern void _UmpShowPrivacyOptionsForm(); + [DllImport("__Internal")] private static extern void _UmpResetConsent(); + [DllImport("__Internal")] private static extern bool _UmpIsPrivacyOptionsRequired(); +#endif + + public bool IsPrivacyOptionsRequired + { + get + { +#if UNITY_EDITOR + return false; +#elif UNITY_ANDROID + using var cls = new AndroidJavaClass(AndroidClass); + return cls.CallStatic("IsPrivacyOptionsRequired"); +#elif UNITY_IOS + return _UmpIsPrivacyOptionsRequired(); +#else + return false; +#endif + } + } + + public UniTask InitializeAsync(UmpInitializeParameters parameters, CancellationToken ct) + { +#if UNITY_EDITOR + return UniTask.FromResult(new UmpResult(UmpConsentStatus.NotRequired)); +#else + return CallAsync(ct, () => NativeInitialize(parameters)); +#endif + } + + public UniTask ShowFormIfRequiredAsync(CancellationToken ct) + { +#if UNITY_EDITOR + return UniTask.FromResult(new UmpResult(UmpConsentStatus.NotRequired)); +#else + return CallAsync(ct, NativeShowFormIfRequired); +#endif + } + + public UniTask ShowPrivacyOptionsFormAsync(CancellationToken ct) + { +#if UNITY_EDITOR + return UniTask.FromResult(new UmpResult(UmpConsentStatus.NotRequired)); +#else + return CallAsync(ct, NativeShowPrivacyOptions); +#endif + } + + public UniTask ResetConsentAsync(CancellationToken ct) + { +#if UNITY_EDITOR +#elif UNITY_ANDROID + using var cls = new AndroidJavaClass(AndroidClass); + cls.CallStatic("ResetConsent"); +#elif UNITY_IOS + _UmpResetConsent(); +#endif + return UniTask.CompletedTask; + } + + private async UniTask CallAsync(CancellationToken ct, Action invokeNative) + { + EnsureReceiver(); + + var tcs = new UniTaskCompletionSource(); + _pending = tcs; + + using (ct.Register(() => tcs.TrySetCanceled(ct))) + { + invokeNative(); + var raw = await tcs.Task; + return Parse(raw); + } + } + + private void EnsureReceiver() + { + if (_receiver != null) + { + return; + } + + var go = new GameObject(GameObjectName); + UnityEngine.Object.DontDestroyOnLoad(go); + _receiver = go.AddComponent(); + _receiver.OnMessage = raw => _pending?.TrySetResult(raw); + } + + private void NativeInitialize(UmpInitializeParameters parameters) + { + var geography = (int)parameters.DebugGeography; + var device = parameters.TestDeviceHashedId ?? string.Empty; +#if UNITY_ANDROID && !UNITY_EDITOR + using var cls = new AndroidJavaClass(AndroidClass); + cls.CallStatic("Initialize", geography, device); +#elif UNITY_IOS && !UNITY_EDITOR + _UmpInitialize(geography, device); +#endif + } + + private void NativeShowFormIfRequired() + { +#if UNITY_ANDROID && !UNITY_EDITOR + using var cls = new AndroidJavaClass(AndroidClass); + cls.CallStatic("ShowFormIfRequired"); +#elif UNITY_IOS && !UNITY_EDITOR + _UmpShowFormIfRequired(); +#endif + } + + private void NativeShowPrivacyOptions() + { +#if UNITY_ANDROID && !UNITY_EDITOR + using var cls = new AndroidJavaClass(AndroidClass); + cls.CallStatic("ShowPrivacyOptionsForm"); +#elif UNITY_IOS && !UNITY_EDITOR + _UmpShowPrivacyOptionsForm(); +#endif + } + + private static UmpResult Parse(string raw) + { + var parts = (raw ?? string.Empty).Split(new[] { '|' }, 5); + var status = (UmpConsentStatus)ParseInt(parts, 1); + var error = ParseInt(parts, 2); + if (error == 0) + { + return new UmpResult(status); + } + + var code = (UmpErrorCode)(error - 1); + var nativeCode = ParseInt(parts, 3); + var message = parts.Length > 4 ? parts[4] : string.Empty; + return new UmpResult(status, new UmpError(code, nativeCode, message)); + } + + private static int ParseInt(string[] parts, int index) + { + if (parts.Length <= index) + { + return 0; + } + + return int.TryParse(parts[index], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value) ? value : 0; + } + } +} diff --git a/src/Runtime/UmpConsentService.cs.meta b/src/Runtime/UmpConsentService.cs.meta new file mode 100644 index 0000000..dcc780f --- /dev/null +++ b/src/Runtime/UmpConsentService.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6af2e100c09795a0ba991f57c9cc554e \ No newline at end of file diff --git a/src/Runtime/UmpTypes.cs b/src/Runtime/UmpTypes.cs new file mode 100644 index 0000000..f1c92b4 --- /dev/null +++ b/src/Runtime/UmpTypes.cs @@ -0,0 +1,64 @@ +namespace Appegy.Ump +{ + public enum UmpConsentStatus + { + Unknown = 0, + NotRequired = 1, + Required = 2, + Obtained = 3 + } + + public enum UmpDebugGeography + { + Disabled = 0, + Eea = 1, + RegulatedUsState = 3, + Other = 4 + } + + public enum UmpErrorCode + { + Network = 0, + FormUnavailable = 1, + FormLoadFailed = 2, + Internal = 3 + } + + public readonly struct UmpError + { + public UmpErrorCode Code { get; } + public int NativeCode { get; } + public string Message { get; } + + public UmpError(UmpErrorCode code, int nativeCode, string message) + { + Code = code; + NativeCode = nativeCode; + Message = message ?? string.Empty; + } + + public override string ToString() + { + return $"{Code} (native {NativeCode}): {Message}"; + } + } + + public readonly struct UmpResult + { + public UmpConsentStatus Status { get; } + public UmpError? Error { get; } + public bool IsSuccess => Error == null; + + public UmpResult(UmpConsentStatus status, UmpError? error = null) + { + Status = status; + Error = error; + } + } + + public struct UmpInitializeParameters + { + public UmpDebugGeography DebugGeography; + public string TestDeviceHashedId; + } +} diff --git a/src/Runtime/UmpTypes.cs.meta b/src/Runtime/UmpTypes.cs.meta new file mode 100644 index 0000000..891757f --- /dev/null +++ b/src/Runtime/UmpTypes.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: faca7c512062794dab3c05d20abdb276 \ No newline at end of file From 3819356123b1b0cb2e80312bb4fd149760873ef9 Mon Sep 17 00:00:00 2001 From: Ivan Murashka Date: Thu, 25 Jun 2026 22:36:48 +0200 Subject: [PATCH 2/2] fix: keep UmpKitConsent from R8 stripping via consumer proguard --- .../Android/UmpKitProguard.androidlib.meta | 2 ++ .../AndroidManifest.xml | 6 ++++++ .../UmpKitProguard.androidlib/build.gradle | 17 +++++++++++++++++ .../UmpKitProguard.androidlib/proguard.txt | 1 + .../project.properties | 2 ++ 5 files changed, 28 insertions(+) create mode 100644 src/Runtime/Plugins/Android/UmpKitProguard.androidlib.meta create mode 100644 src/Runtime/Plugins/Android/UmpKitProguard.androidlib/AndroidManifest.xml create mode 100644 src/Runtime/Plugins/Android/UmpKitProguard.androidlib/build.gradle create mode 100644 src/Runtime/Plugins/Android/UmpKitProguard.androidlib/proguard.txt create mode 100644 src/Runtime/Plugins/Android/UmpKitProguard.androidlib/project.properties diff --git a/src/Runtime/Plugins/Android/UmpKitProguard.androidlib.meta b/src/Runtime/Plugins/Android/UmpKitProguard.androidlib.meta new file mode 100644 index 0000000..a2e4af3 --- /dev/null +++ b/src/Runtime/Plugins/Android/UmpKitProguard.androidlib.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6cf3adc2d443f3c8d8d4f06cecae9524 \ No newline at end of file diff --git a/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/AndroidManifest.xml b/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/AndroidManifest.xml new file mode 100644 index 0000000..865a9a0 --- /dev/null +++ b/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + diff --git a/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/build.gradle b/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/build.gradle new file mode 100644 index 0000000..053712d --- /dev/null +++ b/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/build.gradle @@ -0,0 +1,17 @@ +apply plugin: 'com.android.library' + +android { + namespace "io.appegy.ump.proguard" + compileSdk 36 + + defaultConfig { + minSdk 29 + consumerProguardFiles 'proguard.txt' + } + + lint { abortOnError false } + + sourceSets { + main { manifest.srcFile 'AndroidManifest.xml' } + } +} diff --git a/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/proguard.txt b/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/proguard.txt new file mode 100644 index 0000000..547e6d1 --- /dev/null +++ b/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/proguard.txt @@ -0,0 +1 @@ +-keep class com.appegy.ump.** { *; } diff --git a/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/project.properties b/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/project.properties new file mode 100644 index 0000000..7096c5c --- /dev/null +++ b/src/Runtime/Plugins/Android/UmpKitProguard.androidlib/project.properties @@ -0,0 +1,2 @@ +target=android-9 +android.library=true