Перейти к содержанию

Базовый модуль🔗

Помимо инициализации и сбора статистики, с помощью базового модуля вы также можете получить информацию об устройстве, открыть настройки вашего приложения, показать запрос на разрешение трекинга (IDFA) на iOS 14+, и многое другое. Читайте о возможностях ниже.

Запрос разрешения на трекинг пользователя на iOS 14+🔗

Рекламный идентификатор (IDFA) на iOS позволяет идентифицировать устройство пользователя и отслеживать его активность. Под отслеживанием понимается процесс связывания данных пользователей и устройств, собранных из вашего приложения, с данными, собранными из приложений, веб-сайтов или ресурсов других компаний. Это необходимо для атрибуции трафика и отслеживания конверсий (установок, покупок и т.д.). До iOS 14 пользователь мог на уровне системы ограничить передачу IDFA во все приложения, но это делала малая часть игроков, поэтому мы могли отслеживать большинство. В iOS 14 Apple добавила новый тип разрешений - разрешение на трекинг пользователя, до iOS 14.5 оно необязательно, но начиная с iOS 14.5, чтобы получить IDFA приложение обязано показать пользователю «запрос на отслеживание», и только если пользователь согласился, мы получим IDFA. Подробнее про отслеживание и его примеры можно почитать в официальной документации. С официальной документацией по библиотеке AppTrackingTransparency (ATT) можно ознакомиться здесь

Несколько важных моментов про показ запроса:

  1. Запрос будет показан единожды, вне зависимости от того, сколько раз приложение вызывает метод показа. Поменять свое решение пользователь может только в настройках системы.
  2. Пользователь может как и до iOS 14 ограничить отдачу IDFA приложениям глобально, в таком случае окно запроса даже не покажется. Оно будет показано только когда пользователь изменит данную глобальную настройку.
  3. Запрос можно показать в любой момент работы приложения, не обязательно на старте. Apple рекомендует показывать запрос прямо перед тем, как IDFA действительно понадобится, например, перед показом рекламы, чтобы пользователь понимал, зачем это нужно.
  4. При показе запроса необходимо предоставить строку с описанием/объяснением того, зачем вам нужно отслеживать пользователя. Она указывается в Info.plist приложения, ее можно локализовать.
  5. Запрос влияет только на отдачу IDFA, IDFV будет отдаваться как и раньше

logo

Ниже приведено описание внедрения запроса в ваше приложение:

Шаг 1. Добавление описания🔗

Для того, чтобы показать данный запрос в первую очередь нужно добавить поле NSUserTrackingUsageDescription с описанием того, зачем вам необходимо отслеживать пользователя, в Info.plist приложения. Для этого:

Добавьте следующий код в 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.");
    }
}
Либо вручную добавьте данный параметр в сгенерированном проекте XCode

Добавьте следующий код в UPL file:

<iosPListUpdates>
    <addElements tag="dict">
        <key>NSUserTrackingUsageDescription</key>
        <string>This identifier will be used to deliver personalized ads to you.</string>
    </addElements>
</iosPListUpdates>

Откройте Info.plist приложения в XCode, и добавьте флаг NSUserTrackingUsageDescription в редакторе, либо откройте plist в формате XML, и добавьте туда:

<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>

Локализация запроса

Одна из студий сделала скрипт локализации для Unity, исходный код можно скачать по ссылкам: IosPostBuildProcessor и BuildSettingsConfig

Про локализацию ресурсов в iOS можно почитать по ссылке. Чтобы локализовать их из Unity, нужно копировать в PostBuild в собранный проект XCode уже подготовленные файлы локализации, пример можно найти здесь.

При локализации из Unity могут быть небольшие проблемы с тем, что это "нативная" локализация, а не Unity, поэтому надо у проекта будет выставлять поддерживаемые локализации. Если у вас возникли такие проблемы - можете обратиться к странице MRGSGameCenter, к разделу "Что делать, если возникли проблемы с локализацией на iOS?"

Шаг 2. Проверка необходимости показа🔗

Затем, нужно определить, в какой момент вы хотите показывать данное окно пользователю. Мы рекомендуем показывать окно прямо перед показом рекламы, предварительно рассказав пользователю о том, зачем необходимо данное разрешение. Для проверки необходимости показа диалога запроса разрешения на трекинг у пользователя воспользуйтесь методом:

bool should = MRGSDevice.Instance.ShouldShowTrackingAuthorizationDialog();
bool ShouldShow = FMRGSDevice::Get().ShouldShowTrackingAuthorizationDialog();
BOOL should = [[MRGSDevice currentDevice] shouldShowTrackingAuthorizationDialog];

С помощью него вы можете понять, нужно ли, например, показать предварительный диалог с объяснением того, зачем это нужно, гарантированно зная, что потом запрос будет показан. Рекомендуем всегда перед вызовом метода requestTrackingAuthorizationWithCompletionHandler проверять результат работы данного метода. На версиях до iOS 14 всегда будет возвращен false. На версиях iOS 14 будет возвращен true, если диалог еще не разу не был показан пользователю и false в случаях, когда пользователь видел диалог, или запретил трекинг в настройках.

Важное исключение

На ранних версиях iOS 14 IDFA приходит без запроса разрешения. Диалог в таком случае покажется (если вызвать метод показа), но если мы уже получаем IDFA, то его показывать нет смысла. Поэтому, в случаях, когда IDFA уже получен данный метод вернет false (Для того, чтобы вы могли протестировать поведение метода, такой механизм будет работать только в случае, если при инициализации MRGS флаг showTrackingAuthorizationDialogOnAlliOSVersions выставлен в false.)

Шаг 3. Показ запроса🔗

Для показа окна запроса разрешения на трекинг у пользователя воспользуйтесь методом:

// public void RequestTrackingAuthorization(Action<MRGSIDFATrackingAuthorizationStatus> completion);

MRGSDevice.Instance.RequestTrackingAuthorization((MRGSIDFATrackingAuthorizationStatus status) => {
    // Handle the result
});

Возможные статусы:

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
});

Возможные статусы:

/**
 * 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
}];

Возможные статусы:

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
};

Данное окно показывается только на iOS 14+, на остальных версиях сразу вернется статус Authorized или Restricted, в зависимости от настроек пользователя. Вне зависимости ит количества вызовов, окно показывается только один раз, потом будет просто возвращен текущий статус.

Статистика

При использовании наших методов, MRGS автоматически собирает статистику по показам/соглашениям/отказам с помощью MRGSMetrics (метрика -16)

Получение текущего статуса🔗

Для того, чтобы узнать текущий статус разрешения трекинга MRGSIDFATrackingAuthorizationStatus, воспользуйтесь свойством (На версиях до iOS 14 будет возвращаться статус Authorized или Restricted, в зависимости от настроек пользователя):

// public MRGSIDFATrackingAuthorizationStatus CurrentTrackingAuthorizationStatus { get; set; }

MRGSIDFATrackingAuthorizationStatus status = MRGSDevice.Instance.CurrentTrackingAuthorizationStatus;
#include "MRGSDevice.h"

EMRGSIDFATrackingAuthorizationStatus Status = FMRGSDevice::Get().GetCurrentTrackingAuthorizationStatus();
// @property (nonatomic, readonly, assign) MRGSIDFATrackingAuthorizationStatus currentTrackingAuthorizationStatus;

MRGSIDFATrackingAuthorizationStatus status = [MRGSDevice currentDevice].currentTrackingAuthorizationStatus;

Переход в настройки

Если пользователь уже отказался от трекинга в системном окне, но готов включить его обратно, то вы можете перебросить его прямо в приложение настроек на вкладку вашего приложения с помощью данного метода

Автоматический показ🔗

В случае, если вы хотите показывать окно с запросом разрешения пользователю сразу при старте, то установите соответствующий флаг в настройках MRGS ( в таком случае методы, описанные выше, можно не вызывать):

MRGServiceParams serviceParams = mew MRGServiceParams(appId: MRGS_APP_ID, appSecret: CLIENT_SECRET)  

// Request permission immediately after start 
serviceParams.IOSExtraOptions.AutomaticallyShowIDFARequestAtStartup = true;

// Additional configuration and initialization of MRGS
// ...
#include "MRGSDevice.h"

FMRGServiceParams ServiceParams;

// Request permission immediately after start
ServiceParams.IOSExtraOptions.bShouldRequestIdfaAtStartup = true;

// Additional configuration and initialization of MRGS
// ...
// MRGService settings
MRGServiceParams *mrgsParams = [[MRGServiceParams alloc] initWithAppId: <MRGS_APP_ID> secret: <CLIENT_SECRET>];

// Request permission immediately after start
mrgsParams.automaticallyShowIDFARequestAtStartup = YES;

// Additional configuration and initialization of MRGS
// ...

Получение статуса согласия пользователя на отслеживание с учетом IDFA🔗

Поскольку мы можем показывать запрос разрешения на трекинг не всем пользователям, а только с iOS 14.5+, то для получения текущего статуса согласия удобнее воспользоваться методом: (проверяет наличие IDFA. Если он выдан системой - значит пользователя согласился на отслеживание)

bool hasAgreed = MRGSDevice.Instance.HasUserAgreedToBeTracked();
bool HasAgreed = FMRGSDevice::Get().HasUserAgreedToBeTracked();
BOOL  hasAgreed =  [[MRGSDevice currentDevice] hasUserAgreedToBeTracked];

Важное обобщение

Мы сделали гибкий API, чтобы игры могли сами выбирать, что и как они должны показывать. Но наш основной подход - это сначала проверка необходимости показа, и показ. Метод для проверки необходимости показа проверяет не только то, был ли ранее показан диалог, но и то, получен ли уже IDFA, и если он получен, то показывать не нужно(такова логика нашего метода), чтобы игры могли заранее внедрить эту данную систему, а как только выйдет iOS с обязательным требованием показа запроса (iOS 14.5), то у игр автоматом стали бы появляться окна с запросом. То есть они были бы подготовлены, и когда действительно надо показать - показ был, а на версиях iOS 14, где IDFA и так отдается сам - не показывать(лишний раз не получать отказ). Соответственно с флагом showTrackingAuthorizationDialogOnAlliOSVersions, мы в методе проверки необходимости показа не смотрим на полученный IDFA, чтоб игры могли как то протестировать этот механизм. Это наш заложенный подход.

Но также игры могут сами в любой момент вызывать метод показа окна, и оно покажется (не вызывая наш метод проверки необходимости), а также получить текущий статус, и тд. То есть уже игра сама выбирает, как она хочет показывать этот диалог, хочет показывать на версиях до iOS 14.5 - можно вызвать метод показа.

Открытие настроек приложения🔗

Если вы хотите перенаправить пользователя в системные настройки в раздел настроек вашего приложения (пользователь сразу попадет в место, где сможет быстро изменить настройки уведомлений, геопозиции, трекинга(IDFA на iOS 14+), и другого), воспользуйтесь методом:

MRGSDevice.Instance.OpenSystemSettingsOfApplication();
FMRGSDevice::Get().OpenApplicationSystemSettings();
[MRGSDevice openSystemSettingsOfApplication];
MRGSDevice.getInstance().openSystemSettingsOfApplication();

Открытие системного окна "Поделиться"🔗

MRGS позволяет показать системное окно шеринга данных (share button), а также окно отправки email (на iOS при выборе email будет показано отдельное окно составления письма)

share-dialog-ios share-dialog-android

Поддерживаемые типы данных:

  • Текст/тема
  • Заголовок (только для Android)
  • Ссылки
  • Изображения
  • Файлы
  • Email

Сначала необходимо настроить данные, которыми необходимо поделиться (или отправить письмо), а затем вызвать метод показа и передать туда настроенный ранее объект. Объект результата вернется в хендлер:

// 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.
    }
});

Особенности share поведения

Некоторыми типами данных, например ссылки/изображения/файлы лучше делиться по отдельности для более понятного для пользователя отображения UI. На iOS, также, не все приложения могут принимать массив с объектами, которыми поделился пользователь (например, если поделиться текстом и ссылкой, то действие "копировать" заберет только ссылку, а если выбрать отправку по почте, то в письме будет и текст и ссылка, то есть в некоторых случаях лучше текст и ссылку передавать как одну строку в поле text)

Управление постбеками конверсий SKAdNetwork🔗

Начиная с выхода iOS 14.5 Apple внедряет новую политику использования IDFA (ATT), теперь приложение должно явно запросить у пользователя доступ к данному идентификатору, оценка на пользователей, которые позволят его использовать колеблется около 10-20%. В связи с этим для существенной доли аудитории теряется возможность следить за атрибуцией отдельных пользователей по старым схемам.

На замену Apple предложила свое решение - SKAdNetwork, позволяющее "связать" установки на устройстве пользователя без необходимости отправлять рекламный идентификатор на сервера. Apple с помощью SKAdNetwork сам осуществляет атрибуцию и позволяет получить рекламной сети обезличенный постбек после установки. Сеть может понять что конверсия (постбек) осуществилась по какой-то кампании, но не будет знать по какому пользователю.

logo

MRGS позволяет проектам:

  • гибко настроить правила расчета и установки conversionValue, при чем настройка, включение происходит удаленно на сервере, без обновления клиента;
  • выставить conversionValue;
  • собрать статистику.

Подробнее про работу с SKAdNetwork читайте на отдельной странице

Получение разных данных об устройстве, сервере, и другое🔗

Информация об устройстве🔗

С помощью класса MRGSDevice вы можете получить следующие данные об устройстве:

// 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;
// Get the device locale
MRGSDevice.getInstance().getCountry();

// Get the device name
MRGSDevice.getInstance().getModel();

// Get platform name
MRGSDevice.getInstance().getPlatform();

Note

На нативных платформах параметров для получения еще больше, поэтому смотрите в заголовочные файлы нативных классов.

А также получить уникальный идентификатор устройства, который использует MRGS:

// Callback way
MRGSDevice.Instance.GetOpenUDID(udid => {
    // Handle the result
});

// Async/await way
var openUdid = await MRGSDevice.Instance.GetOpenUDIDAsync();
// Callback way
FMRGSDevice::Get().GetOpenUDID([](FString Udid) {
    // Handle the result          
});
// + (NSString*)openUDID;
NSString* udid = [MRGSDevice openUDID];
// public interface CallbackOpenUDID {
//     void result(String openUDID);
// }

MRGSDevice.getInstance().getOpenUDID(CallbackOpenUDID);

Получение идентификаторов IDFA/IDFV🔗

Чтобы получить рекламный идентификатор устройства (IDFA) или идентификатор для издателя (IDFV. Только на iOS), воспользуйтесь полями:

// 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
[[MRGSDevice currentDevice] advertisingIdentifier];

// IDFV
[[MRGSDevice currentDevice] identifierForVendor];
// 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 stores.
MRGSDevice.getInstance().getVendorId(Context, OnVendorIdCallback);

Информация о приложении🔗

Также вы можете получить данные о серверном времени, и URL, с которым было запущено приложение:

// Returns INSTALL_REFERER for Android,
// and for iOS, the URL with which the application was launched
MRGService.Instance.GetInstallReferer();
// Returns INSTALL_REFERRER for Android, 
// and for iOS, the URL with which the application was launched
FMRGService::Get().GetInstallReferrer();
// The URL with which the application was launched
[MRGService sharedInstance].launchedUrl;
// Returns INSTALL_REFERER.
MRGSBroadcastReceiver.restoreReferer();

Серверное время🔗

MRGS позволяет Вам получить актуальное серверное время в любой момент работы приложения.

// Get the server time at the current moment.
// It will return the real current, not cached server time
MRGService.Instance.ServerTime;
// Get the server time at the current moment.
// It will return the real current, not cached server time
FMRGService::Get().GetServerTime();
// Get the server time at the current moment.
// It will return the real current, not cached server time
[MRGService sharedInstance].serverTime;
// Get the server time at the current moment.
// It will return the real current, not cached server time
MRGService.getInstance().getServerTime();

Причины из-за которых вернулось серверное время 0

  1. Самый первый запуск приложения, так как чтобы серверное время было отличное от 0, нужно чтобы выполнился хотя бы один сетевой запрос на сервер MRGS.
  2. iOS кэширует серверное время в файловую систему после его первого получения. Но если устройство будет перезагружено или пользователь вручную переведет время на устройстве(и перезагрузит приложение), то серверное время может придти 0, если обращение будет сделано до того как придет сетевой ответ от сервера
  3. Android хранит серверное время только на время сессии, потому при любом первом запуске приложения может прийти 0, если обращение будет сделано до того как придет сетевой ответ от сервера.

Замечание

Обратите внимание, что время пересчитывается каждый раз когда приходит сетевой ответ от сервера. Из-за того что сервер кэширует время и обновляет его раз в минуту, можно наблюдать некоторые "скачки времени", когда время сбрасывается на несколько секунд до 1 минуты назад.

Географическое положение по IP🔗

MRGS позволяет вам получить географическое положение устройства с доступом в Интернет по его IP-адресу. Результат запроса возвращается в формате двухбуквенного кода страны по стандарту 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();
FMRGSDevice::Get().GetGeoIpInfo([](FGeoInfoPtr GeoInfo, FErrorPtr Error)
{
    if (GeoInfo.IsValid())
    {
        UE_LOG(LogTemp, Verbose, TEXT("MRGSDevice - MRGSGeoIpInfo success: %s"), GeoInfo->Country);
    }
    else
    {
        UE_LOG(LogTemp, Verbose, TEXT("MRGSDevice - MRGSGeoIpInfo failed: %s"), Error->Message);
    }
});
[[MRGSDevice currentDevice] getGeoIpInfo:^(MRGSGeoIpInfo* _Nullable info, NSError* _Nullable error) {
    if(!error){
        NSLog(@"Received geoIp info: %@", info);
    }else{
        NSLog(@"Received geoIp error: %@", error.localizedDescription);
    }
}];
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);
        }
    }
    });

Замечание

Результат запроса кэшируется в RAM на всю сессию приложения, поэтому если вы используете VPN для тестирования, вам нужно перезапустить приложение, чтобы получить новый результат.

Время установки приложения🔗

MRGS хранит время установки приложения. Для того чтобы получить время, достаточно обратиться к следующим функциям:

// Unix time in seconds
var installTimeInSec = MRGSApplication.Instance.InstallTime;
// Unix time in seconds
int64 InstallTimeInSec = FMRGSApplication::Get().GetInstallTime();
NSDate *installDate = [NSDate dateWithTimeIntervalSince1970:[MRGSApplication currentApplication].applicationInstallTime];
import games.my.mrgs.MRGSApplication;

// Unix time in milliseconds
final long installTimeInMs = MRGSApplication.getInstance().getInstallTime();

Последнее обновление: 2025-01-21
Дата создания: 2020-09-23