Android - Installation Source - Monitor (Pro)
A player can download your app, edit it, and install that copy from somewhere else. This monitor finds which store installed the app.
Walkthrough: Protecting an Android build.
Monitor
AndroidPackageSourceMonitor (namespace GUPS.AntiCheat.Monitor.Android) finds where the app was installed from. It then sends an AndroidSourceStatus. That status has the store name and the store's package name. If the store is not in the known list, EAppStore.Unknown is used. You can still read the raw package name.
Status
The monitor sends an AndroidSourceStatus:
public struct AndroidSourceStatus : IAndroidStatus
{
// True if the installer could not be retrieved (e.g. a JNI failure).
public bool FailedToRetrieveData { get; }
// The recognized app store, or EAppStore.Unknown.
public EAppStore AppStoreSource { get; }
// The raw installer package name reported by the OS.
public string AppStoreSourcePackage { get; }
}
- FailedToRetrieveData: The source could not be read. The other values are not valid.
- AppStoreSource: A known store, or
Unknown. See the table below. - AppStoreSourcePackage: The raw package name. Useful when the store is
Unknown.
Lifecycle and timing
The monitor checks once, when it starts. It then sends one AndroidSourceStatus. If the check fails, it still sends a status, with FailedToRetrieveData set to true.
Configuration
This monitor has no Inspector fields. The allowed stores are set in Project Settings. The detector uses that list. Open Edit > Project Settings > GuardingPearSoftware > AntiCheat and go to Android - App Store - Settings.

Allowed install sources.
Development builds
Verify development builds is off by default. While it is off, the check skips development builds and the Editor. Turn it on while you test.

Turn on Verify development builds to also check development builds and the Editor.
Supported platforms
Android only.
Requirements
Android 4.4 (API level 19) or newer.
How to use
Add AndroidPackageSourceMonitor as a child of the AntiCheat-Monitor. Pair it with AndroidPackageTamperingDetector.
Add the component
Add AndroidPackageSourceMonitor from GUPS.AntiCheat.Monitor.Android. A child of the monitor is the best place.

Add the AndroidPackageSourceMonitor component.
Known stores
These stores are recognized by default. Anything else is Unknown.
| Store | What it is |
|---|---|
| Android Package Installer | The system installer. Used when the app came from an APK file, not a store |
| Amazon Appstore | Amazon's store |
| Aptoide | An independent Android store |
| Cafe Bazaar | An Iranian Android store |
| F-Droid | An open-source Android store |
| Google Play Store | Google's store |
| Huawei AppGallery | Huawei's store |
| Myket | An Android store |
| Oppo App Market | Oppo's store |
| Samsung Galaxy Store | Samsung's store |
| TapTap | A store for mobile games |
| Vivo App Store | Vivo's store |
| Xiaomi Mi GetApps | Xiaomi's store |
| XDA Labs | A store for development projects |
| Unknown | None of the stores above |
Read the status in code
You can also listen yourself. Subscribe returns an IDisposable. Dispose it when you want to stop.
using System;
using GUPS.AntiCheat.Core.Watch;
using GUPS.AntiCheat.Monitor.Android;
using UnityEngine;
public class AndroidSourceStatusLogger : MonoBehaviour, IObserver<IWatchedSubject>
{
private void Start()
{
var monitor = GetComponentInChildren<AndroidPackageSourceMonitor>();
monitor.Subscribe(this);
}
public void OnNext(IWatchedSubject subject)
{
if (subject is AndroidSourceStatus status)
{
if (status.FailedToRetrieveData)
{
Debug.LogWarning("Could not resolve the installation source.");
return;
}
Debug.Log($"Installed from: {status.AppStoreSource} ({status.AppStoreSourcePackage})");
}
}
public void OnError(Exception error) { }
public void OnCompleted() { }
}
Detect a store you do not allow
To decide if the store is allowed, use the Android package tampering detector.