Core module🔗
In addition to initialization and collecting statistics, using the base module, you can also get device information, open your app's settings, show a tracking permission request (IDFA) on iOS 14+, and much more. Read about the features below.
Request permission to track user on iOS 14+🔗
Advertising Identifier (IDFA) on iOS allows you to identify a user's device and track its activity. Tracking refers to the process of linking user and device data collected from your application with data collected from applications, websites, or third-party resources. This is necessary for attributing traffic and tracking conversions (installs, purchases, etc.). Before iOS 14, a user could at the system level restrict the transfer of IDFA to all applications, but only a small percentage of players did this, so we could track the majority. In iOS 14, Apple added a new type of permission - permission to track the user, it's not required before iOS 14.5, but starting from iOS 14.5, in order to receive an IDFA, the application must show the user a "tracking request", and only if the user has agreed, we will receive the IDFA. You can read more about tracking and its examples in the official documentation. The official documentation for the AppTrackingTransparency (ATT) library can be found here
A few important points about displaying a request:
- The request will be shown once, regardless of how many times the application calls the show method. The user can change his decision only in the system settings.
- The user can, as before iOS 14, restrict the return of IDFA to applications globally, in which case the request window will not even appear. It will only be shown when the user changes this global setting.
- The request can be shown at any time when the application is running, not necessarily at the start. Apple recommends showing the request right before the IDFA is actually needed, for example, before showing ads, so that the user understands why it is needed.
- When displaying a request, you must provide a string describing / explaining why you want to track the user. It is specified in the Info.plist of the application and can be localized.
- The request only affects the return of IDFA, IDFV will be sent as before

Below is a description of how to embed a request into your application:
Step 1. Add description🔗
In order to show this request, first of all, you need to add the NSUserTrackingUsageDescription field with a description of why you need to track the user to the Info.plist of the application. For this:
Add the following code to PostProcessBuild:
public class MRGSPostBuildProcessSample
{
[PostProcessBuild]
public static void PostProcessBuild(BuildTarget target, string path)
{
string plistPath = path + "/Info.plist";
PlistDocument plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(plistPath));
PlistElementDict rootDict = plist.root;
// Adding descriptions
rootDict.SetString("NSUserTrackingUsageDescription",
"This identifier will be used to deliver personalized ads to you.");
}
}
Add the following code to UPL file:
Localization of the request
One of the studios made a localization script for Unity, the source code can be downloaded from the links: IosPostBuildProcessor and BuildSettingsConfig
You can read about resource localization in iOS at the link. To localize them from Unity, you need to copy the already prepared localization files into PostBuild into the assembled XCode project, an example can be found here.
When localizing from Unity, there may be minor problems with the fact that this is a "native" localization, and not Unity, so the project will need to expose supported localizations. If you have such problems, you can refer to the page MRGSGameCenter, back to "What to do if you have problems localizing on iOS?"
Step 2. Checking the need to show🔗
Then, you need to determine at what point you want to show this window to the user. We recommend showing the window right before displaying ads, having previously told the user why this permission is needed. To check the need to display the dialog for requesting permission for tracking from the user, use the method:
With the help of it, you can understand whether, for example, you need to show a preliminary dialog with an explanation of why it is needed, knowing for sure that the request will be shown later. We recommend that you always check the result of this method before calling the requestTrackingAuthorizationWithCompletionHandler method. Pre-iOS 14 will always return false. On versions of iOS 14, it will return true if the dialog has not been shown to the user yet and false if the user has seen the dialog or disabled tracking in the settings.
Important exception
On early versions of iOS 14, IDFA arrives without asking for permission. In this case, the dialog will appear (if you call the show method), but if we already get the IDFA, then there is no point in showing it. Therefore, in cases where IDFA has already been received, this method will return false (In order for you to test the behavior of the method, this mechanism will only work if the showTrackingAuthorizationDialogOnAlliOSVersions flag is set to false during MRGS initialization.)
Step 3. Displaying the request🔗
To display the window for requesting permission for tracking from the user, use the method:
// public void RequestTrackingAuthorization(Action<MRGSIDFATrackingAuthorizationStatus> completion);
MRGSDevice.Instance.RequestTrackingAuthorization((MRGSIDFATrackingAuthorizationStatus status) => {
/// Handle the result
});
Possible statuses:
public enum MRGSIDFATrackingAuthorizationStatus
{
/// Request window wasn't shown to user at all
NotDetermined = 0,
/// User switched off tracking in device settings
Restricted = 1,
/// User asked app not to track in request window (or later in device settings)
Denied = 2,
/// User has granted permission to track
Authorized = 3,
}
#include "MRGSDevice.h"
FMRGSDevice::Get().RequestTrackingAuthorization([](EMRGSIDFATrackingAuthorizationStatus Status) {
// Handle the result
});
Possible statuses:
/**
* Describe the status of the user's tracking permission request (IDFA request on iOS 14+).
*/
enum MRGSERVICE_API EMRGSIDFATrackingAuthorizationStatus
{
/**
* Request window was not shown to user at all.
*/
NotDetermined = 0,
/**
* User switched off tracking in device settings.
*/
Restricted = 1,
/**
* User asked app not to track in request window (or later in device settings).
*/
Denied = 2,
/**
* User has granted permission to track.
*/
Authorized = 3
};
// - (void)requestTrackingAuthorizationWithCompletionHandler:(void (^)(MRGSIDFATrackingAuthorizationStatus status))completion;
[[MRGSDevice currentDevice] requestTrackingAuthorizationWithCompletionHandler:^(MRGSIDFATrackingAuthorizationStatus status) {
// Process result
}];
Possible statuses:
typedef NS_ENUM(NSUInteger, MRGSIDFATrackingAuthorizationStatus) {
/// Request window wasn't shown to user at all
MRGSIDFATrackingAuthorizationStatusNotDetermined = 0,
/// User switched off tracking in device settings
MRGSIDFATrackingAuthorizationStatusRestricted,
/// User asked app not to track in request window (or later in device settings)
MRGSIDFATrackingAuthorizationStatusDenied,
/// User has granted permission to track
MRGSIDFATrackingAuthorizationStatusAuthorized
};
This window is shown only on iOS 14+, on other versions the Authorized or Restricted status will immediately return, depending on the user's settings. Regardless of the number of calls, the window is shown only once, then the current status will simply be returned.
Statistics
When using our methods, MRGS automatically collects statistics on shows/agreements/declines using MRGSMetrics (metricID -16)
Getting current status🔗
In order to find out the current tracking permission status MRGSIDFATrackingAuthorizationStatus, use the property (On versions before iOS 14, the Authorized or Restricted status will be returned, depending on the user settings):
Go to settings
If the user has already abandoned tracking in the system window, but is ready to turn it back on, then you can transfer it directly to the settings application on the tab of your application using using this method
Automatic display🔗
If you want to show a window asking for permission to the user immediately at startup, then set the appropriate flag in the MRGS settings (in this case, the methods described above can not be called):
Obtaining user consent status for tracking based on IDFA🔗
Since we can show a request for tracking permission not to all users, but only with iOS 14.5+, then to obtain the current consent status, it is more convenient to use the method: (checks for the presence of IDFA. If it is issued by the system, then the user could be tracked)
Important generalization
We made a flexible API so that games can choose what they should display and how. But our main approach is to first check the need for a show, and show it. The method for checking the need to show checks not only whether the dialog was shown earlier, but also whether the IDFA has already been received, and if it is received, then it is not necessary to show it (this is the logic of our method) so that games can implement this given system as early as possible. and as soon as iOS comes out with the mandatory requirement to show the request (iOS 14.5), then the games would automatically start to appear with request windows. That is, they would have been prepared, and when it really needed to be shown, there was a show, but on versions of iOS 14, where IDFA is already given itself, do not show it (do not get rejected once again). Accordingly, with the showTrackingAuthorizationDialogOnAlliOSVersions flag, in the method for checking the need for showing, we do not look at the received IDFA, so that the games can somehow test this mechanism. This is our inherent approach.
But also games can themselves call the window show method at any time, and it will appear (without calling our method for checking the need), as well as poll the current status, and so on. That is, the game itself chooses how it wants to show this dialog, wants to show it on versions up to iOS 14.5 - you can call the show method.
Opening Application Settings🔗
If you want to redirect the user to the system settings in the settings section of your application (the user will immediately be taken to a place where he can quickly change the settings for notifications, geolocation, tracking (IDFA on iOS 14+), and others), use the method:
Opening the "Share" system window🔗
MRGS allows you to show the system window for sharing data (share button), as well as the window for sending email (on iOS, when you select email, a separate window for composing a letter will be shown)

Supported data types:
- Text/subject
- Title (Android only)
- Links
- Images
- Files
First you need to set up the data that you want to share (or send an email), and then call the show method and pass the previously configured object there. The result object will return to the handler:
// Setting options
var options = new MRGSShareOptions()
{
Text = "Hello from MRGS!",
Subject = "MRGS Sample App",
Title = "MRGS Share Title",
Url = "https://mrgs.astrum.team",
EmailRecipients = new List<string>{"games.services@my.games"}
};
var image = new Texture2D(128, 128);
options.AddImage(image);
var soundFilePath = System.IO.Directory.GetParent(Application.dataPath) + "/" + "CustomNotificationSound.caf";
options.AddFile(soundFilePath);
// Show dialog
MRGSApplication.Instance.Share(options, (result, error) =>
{
Debug.Log("MRGSApplication#Share Result - " + result + ". Error - " + error);
});
// Setting options
MRGSShareOptions* options = [[MRGSShareOptions alloc] init];
options.text = @"Hello from MRGS!";
options.subject = @"MRGS Sample App";
options.url = @"https://mrgs.astrum.team";
[options addImage:[UIImage imageNamed:@"MRGSLogo"] withName:@"Logo.png"];
[options addFile:[[NSBundle mainBundle] URLForResource:@"custom_coppa_birthday" withExtension:@"html"].path];
options.emailRecipients = @[@"games.services@my.games"];
// Show dialog
[[MRGSApplication currentApplication] share:options completionHandler:^(MRGSShareResult * _Nullable result, NSError * _Nullable error) {
NSLog(@"Received share result - %@", result);
}];
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.File;
import java.util.Collections;
import games.my.mrgs.MRGSApplication;
import games.my.mrgs.MRGSError;
import games.my.mrgs.MRGSShareOptions;
import games.my.mrgs.MRGSShareResult;
import games.my.mrgs.utils.optional.BiConsumer;
// Setting options
final File imageFile = new File("path_to_my_image");
final MRGSShareOptions shareOptions = MRGSShareOptions.newBuilder()
.setTitle("MRGS Share Title")
.setSubject("MRGS Subject")
.setText("Some text for image")
.setFiles(Collections.singletonList(imageFile.getPath()))
.setEmailRecipients(Collections.singletonList("test@test.test"))
.build();
// Show dialog
MRGSApplication.getInstance().share(context, shareOptions, new BiConsumer<MRGSShareResult, MRGSError>()
{
@Override
public void accept(@NonNull MRGSShareResult result, @Nullable MRGSError error) {
// Handle result here.
}
});
Features of share behavior
Some data types, such as links/images/files, are best shared separately for a more user-friendly display of the UI. On iOS, also, not all applications can accept an array with objects shared by the user (for example, if you share text and a link, then the "copy" action will take only the link, and if you choose to send by mail, then the message will contain both text and link, that is, in some cases it is better to send the text and the link as one line in the text field)
Managing postbacks for SKAdNetwork🔗
Starting with the release of iOS 14.5, Apple is introducing a new IDFA (ATT) policy, now the application must explicitly ask the user for access to this identifier, the rating for users that will allow using it fluctuates around 10-20%. In this regard, for a significant share of the audience, the ability to track the attribution of individual users according to the old schemes is lost.
To replace Apple, it offered its solution - SKAdNetwork, which allows you to "link" installations on the user's device without the need to send an advertising identifier to the server. Apple, with the help of SKAdNetwork, itself carries out the attribution and allows the ad network to receive an impersonal postback after installation. The network may understand that the conversion (postback) was carried out for some kind of campaign, but it will not know which user.

MRGS allows projects to:
- flexibly configure the rules for calculating and installing conversionValue, and the setting, the inclusion occurs remotely on the server, without updating the client;
- set conversionValue;
- collect statistics.
Read more about working with SKAdNetwork on a separate page
Getting various data about the device, server, etc.🔗
Device information🔗
Using the MRGSDevice class, you can get the following device data:
// Getting the device locale
string MRGSDevice.Instance.Country;
// Get the device name
string MRGSDevice.Instance.Model;
// Get platform name
string MRGSDevice.Instance.Platform;
// If the device is jailbroken (worth a jailbreak), then true will return.
bool MRGSDevice.Instance.HasJailbreak;
// Convert SystemLanguage to ISO 639-1 format ("german" -> "de").
string MRGSUtils.SystemLanguageToISO(SystemLanguage language);
// Getting the device locale
FString FMRGSDevice::Get().GetCountry();
// Get the device name
FString FMRGSDevice::Get().GetDeviceModel();
// Get platform name
FString FMRGSDevice::Get().GetPlatform();
// If the device is jailbroken (worth a jailbreak), then true will return.
bool FMRGSDevice::Get().HasJailbreak();
// Getting the device locale
+ (NSString*)country;
// String representation of the device name
@property (nonatomic, readonly, copy) NSString* model;
// Get platform name
@property (nonatomic, readonly, copy) NSString* platform;
// If the device is jailbroken (worth a jailbreak), then true will return.
- (BOOL)isDeviceJailbreak;
Note
On native platforms, there are even more parameters to get, so look in the header files of the native classes.
And also get the unique identifier of the device that MRGS uses:
Getting IDFA/IDFV🔗
To get the advertising device ID (IDFA) or publisher ID (IDFV. IOS only), use the following fields:
// IDFA synchronous way
MRGSDevice.Instance.AdvertisingIdentifier;
// Asynchronous way
// Return IDFA for Apple store, GAID for Amazon, Google and Samsung stores, OAID for Huawei store,
// or null for other stores.
MRGSDevice.Instance.GetIdentifierForAdvertising(Action<string, MRGSError>);
// Async/await way
var (id, error) = await MRGSDevice.Instance.GetIdentifierForAdvertisingAsync();
var id = await MRGSDevice.Instance.GetIdentifierForAdvertisingAsync().Throwable();
// IDFV only iOS
MRGSDevice.Instance.IdentifierForVendor;
// Return IDFV for Appse store, AppSet id for Google store, ODID for Huawei store or null for other stores.
MRGSDevice.Instance.GetIdentifierForVendor(Action<string, MRGSError>);
// Async/await way
var (id, error) = await MRGSDevice.Instance.GetIdentifierForVendorAsync();
var id = await MRGSDevice.Instance.GetIdentifierForVendorAsync().Throwable();
// Return IDFA for Apple store, GAID for Amazon, Google and Samsung stores, OAID for Huawei store,
// or null for other stores.
FMRGSDevice::Get().GetAdvertisingId(TFunction<void(FAdvertisingIdPtr, FErrorPtr)>);
// Return IDFV for Appse store, AppSet id for Google store, ODID for Huawei store or null for other stores.
FMRGSDevice::Get().GetVendorId(TFunction<void(FAdvertisingIdPtr, FErrorPtr)>);
// IDFA
// Return an advertising identifier (GAID for Amazon, Google, Samsung stores
// or OAID for Huawei store). For other storages will return null.
MRGSDevice.getInstance().getAdvertisingId(Context, AdvertisingIdCallback);
// Return AppSet id for Google store, ODID for Huawei store or null for other sotores.
MRGSDevice.getInstance().getVendorId(Context, OnVendorIdCallback);
Application Information🔗
Also, you can get data about the server time, and the URL with which the application was launched:
Server time🔗
MRGS allows you to get up-to-date server time at any time when the application is running.
The reasons why the server time returned 0
- The very first launch of the application, since in order for the server time to be different from 0, it is necessary that at least one network request to the MRGS server is executed.
- iOS caches server time to the file system after it is first received. But if the device is rebooted or the user manually transfers the time on the device (and restarts the application), then the server time may come to 0 if the request is made before the network response from the server arrives
- Android stores server time only for the duration of the session, therefore, at any first launch of the application, 0 may come if the request is made before the network response from the server arrives.
Note
Please note that the time is recalculated every time a network response from the server arrives. Due to the fact that the server caches the time and updates it once a minute, you can observe some "time jumps" when the time is reset by a few seconds to 1 minute ago.
Geographical location by IP🔗
MRGS allows you to get the geographical location of the device with Internet access by its IP address. The query result is returned in two-letter country code ISO 3166-1 alpha-2.
// Callback way
MRGSDevice.Instance.GetGeoIpInfo((geoIpInfo, error) => {
if (geoIpInfo != null)
{
Debug.Log("MRGSDevice - MRGSGeoIpInfo success: " + geoIpInfo);
}
else
{
Debug.Log("MRGSDevice - MRGSGeoIpInfo failed: " + error);
}
});
// Async/await way
var (geoIpInfo, error) = await MRGSDevice.Instance.GetGeoIpInfoAsync();
// or with throw Exception
var geoIpInfo = await MRGSDevice.Instance.GetGeoIpInfoAsync().Throwable();
import android.util.Log;
import androidx.annotation.Nullable;
import games.my.mrgs.MRGSDevice;
import games.my.mrgs.MRGSError;
import games.my.mrgs.MRGSGeoIpInfo;
import games.my.mrgs.utils.optional.BiConsumer;
MRGSDevice.getInstance().getGeoIpInfo(new BiConsumer<MRGSGeoIpInfo, MRGSError>() {
@Override
public void accept(@Nullable MRGSGeoIpInfo geoIpInfo, @Nullable MRGSError error) {
if (geoIpInfo != null) {
Log.d("MRGSDevice", "MRGSGeoIpInfo success: " + geoIpInfo);
} else {
Log.d("MRGSDevice", "MRGSGeoIpInfo failed: " + error);
}
}
});
Note
The result of the request is cached in RAM for the entire application session, so if you use a VPN for testing, you need to restart the application to get a new result.
Application install time🔗
MRGS stores the application installation time. To get time, it's enough to call following functions:
Created: 2020-09-23