Русский
Русский
English
Статистика
Реклама

Google mobile services

Знакомство с App Gallery. Создаем аккаунт разработчика

22.09.2020 18:18:39 | Автор: admin


Что происходит, кто виноват и что делать


Недавно Google прекратил сотрудничество с Huawei. Это привело к тому, что Huawei на своих новых девайсах уже не может использовать сервисы Google (магазин приложений, геолокация, карты, пуши, аналитика etc), что для пользователя превращает девайс в кирпич. Если бы это не была китайская компания, то, скорее всего, на этом её бизнес, связанный с Android, просто бы прекратился. Но компания китайская, большая и они пошли по пути импортозамещения, в кратчайшие сроки реализовав функционал, аналогичный Google сервисам.


В этой серии статей мы хотим поделиться своим опытом использования Huawei Mobile Services в уже готовом приложении, использующем Google Mobile Services для аналитики (Firebase Analytics), карт и геолокации. Текста получилось довольно много и о сильно разных сервисах, засим статей будет несколько. Начнём мы с основ регистрации аккаунта разработчика и базовых вещей в коде.


  1. Создаём аккаунт разработчика, подключаем зависимости, подготавливаем код к внедрению. вы тут
  2. Встраиваем Huawei Analytics.
  3. Используем геолокацию от Huawei.
  4. Huawei maps. Используем вместо Google maps для AppGallery.

Если вам интересно узнать технических подробностей, посмотреть код и узнать про подводные камни добро пожаловать под кат!


Что нужно для успешного внедрения


Всё было бы просто, если бы приложение писалось с нуля и не нужно было бы поддерживать как Google так и Huawei. Но мы живём в реальном мире и без сложностей не обойтись. Однако дело сильно упростится, если соблюдён ряд условий.


Но перед перечислением условий надо составить ТЗ. Оно у нас получилось такое:


  1. Нам нужно получить 2 версии APK одну для Google Play, с библиотеками от Google, другую для AppGallery, с библиотеками от Huawei.
  2. В приложении уже используется Firebase Analytics. Надо его заменить на аналог от Huawei.
  3. Есть определение местоположения пользователя. Аналогично заменяем на аналог.
  4. Есть карты. Нужно также заменить на аналог, по максимуму сохранив функционал, т.к. в реализации от Huawei некоторые вещи ещё не сделаны.

А вот что сильно сократит прикладываемые усилия:


  1. Код должен быть написан хорошо. И быть без багов (хотя это само собой разумеется зачем код с багами писать?). Под хорошо будем подразумевать более-менее стандартную архитектуру, мимикрирующую под Clean.
  2. Если код из Google библиотек размазан ровным слоем по всему проекту, то у меня для вас плохие новости. Например у вас может не быть абстракции над аналитикой и/или над полученными от Google координатами. В этом случае придётся её завести, чтобы почистить код от импортов гугловых классов, которые будут недоступны, когда мы уберём их из сборки.
  3. Использование DI. Очень упрощает абстрагирование над аналитикой и геолокацией. Используем интерфейсы, через DI передавая нужную реализацию.
  4. Карты не слишком сильно кастомизированы. В частности, основная сложность будет с абстрагированием над кластеризацией маркеров.

Подготовка к внедрению


Как и в случае с Google, надо зарегистрироваться, создать проект приложения, получить файл конфигурации.


  1. Регистрируемся на https://developer.huawei.com. Тут понадобится паспорт/права + пластиковая карта. День-два вас будут проверять, потом аккаунт заработает. Если вдруг что-то пойдёт не так (забудете что-то указать или укажете неправильно) вам напишут и подробно объяснят. После общения с Google Play всё выглядит очень круто русскоязычная техподдержка отвечает быстро и по делу.
  2. Принимаем всякие соглашения об обработке персональных данных. Внимательно читая, конечно же)
  3. Создаём проект приложения, указывая пакет (он же ApplicationId).
  4. Если вам нужно ещё и встроенные покупки реализовать то надо: а) Заполнить данные банковского счёта б) Распечатать и заполнить заявление о трансграничной передаче персональных данных в КНР в) Отправить скан оного вместе с данными из пункта а г) Отправить заявление из пункта б по почте в Москву. Когда заявление дойдёт вам придёт e-mail и останется только активировать сервис в настройках проекта. На почте бывают накладки возможно, придётся подождать. Я пару недель ждал, потом позвонил ответственному за это в Huawei уверили, что проблему решат. И решили. На русском тоже всё общение очень круто)
  5. Включаем сервис аналитики. В отличие от геолокации и карт, включённых по умолчанию, это нужно сделать вручную.
  6. Добавляем SHA-256 для всех ключей, которыми будет подписано приложение. Т.е. дебажные ключи и релизный ключ.
  7. Скачиваем аналог google-services.json, в случае Huawei называемый agconnect-services.json
  8. Создаём разные flavors для Google и Huawei. Наконец-то можно перейти к коду:

В build.gradle (module app) создаём flavors и указываем, что в папках src/google/kotlin, src/google/res, src/huawei/kotlin, src/huawei/res также находиться будет наш код.


android {  ...  sourceSets {      google.java.srcDirs += 'src/google/kotlin'      google.res.srcDirs += 'src/google/res'      huawei.java.srcDirs += 'src/huawei/kotlin'      huawei.res.srcDirs += 'src/huawei/res'  }  flavorDimensions "store"  productFlavors {      google {          dimension "store"      }      huawei {          dimension "store"      }  }}

Также создаём папки src/huaweiDebug и src/huaweiRelease. В них помещаем наш файл конфигурации agconnect-services.json


И добавляем apply plugin: 'com.huawei.agconnect' в конец build.gradle (module app).


И наконец, добавляем в build.gradle проекта:


buildscript {    ...    repositories {        ...        maven {url 'https://developer.huawei.com/repo/'}    }    dependencies {        ...        classpath 'com.huawei.agconnect:agcp:1.2.1.301'    }}allprojects {    repositories {        ...        maven {url 'https://developer.huawei.com/repo/'}    }}

В следующей части встраиваем аналитику


Теперь мы полностью готовы. У нас есть 2 разных варианта сборки для Huawei и Google. У нас подключены необходимые зависимости. Созданы папки, где будет наш код. Создан аккаунт разработчика и выполнены необходимые действия по созданию проекта приложения. У нас даже какое-то ТЗ есть. И мы уже выполнили первый пункт из ТЗ! Отличный повод на этом статью закончить. И уже в следующей встроить аналитику не от Google, а от Huawei.


Весь код, который есть в этом цикле статей вы можете посмотреть в репозитории на GitHub. Вот ссылка.

Подробнее..

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

06.10.2020 18:23:53 | Автор: admin

image


В прошлой статье мы создавали аккаунт разработчика для использования Huawei Mobile Services и подготавливали проект к их использованию. Теперь пора приступить к встраиванию конкретных сервисов.


Вот полный список статей из цикла:


  1. Создаём аккаунт разработчика, подключаем зависимости, подготавливаем код к внедрению. тык
  2. Встраиваем Huawei Analytics. вы тут
  3. Используем геолокацию от Huawei.
  4. Huawei maps. Используем вместо Google maps для AppGallery.

Как должен выглядеть код в уже готовом проекте


Начнём с аналитики. И исходить будем из того, что она у вас спрятана за примерно такой абстракцией:


interface Analytics {    fun send(event: AnalyticsEvent)}interface AnalyticsEvent {    val key: String    val data: Map<String, Any>}fun Map<String, Any>.toBundle() =    Bundle().apply {        forEach { (key, value) ->            when (value) {                is String -> putString(key, value)                is Int -> putInt(key, value)                is Boolean -> putBoolean(key, value)                is Double -> putDouble(key, value)                is Float -> putFloat(key, value)                else -> throw IllegalArgumentException("Unknown data type: ${value::class.simpleName}")            }        }    }open class SimpleEvent(override val key: String) : AnalyticsEvent {    override val data: Map<String, Any> = hashMapOf()    override fun toString(): String = "AnalyticsEvent { key = $key, data = $data }"}open class ParamsEvent(key: String, vararg params: Pair<String, Any>): SimpleEvent(key) {    override val data = params.toMap()}class EventOpenSomeScreen : SimpleEvent("screen_some_screen")

Соответственно, где требуется какое-то событие отправить, вы делаете что-то такое:


@Injectlateinit var analytics: Analytics...analytics.send(EventOpenSomeScreen())

Используем разные реализации аналитики


Если всё вышеописанное верно, то подставлять разные реализации аналитики в разных сборках проще простого.


  1. Указываем, что для huawei flavor-а мы используем одну библиотеку, а для google другую:

dependencies {  huaweiImplementation 'com.huawei.agconnect:agconnect-core:1.3.1.300'  huaweiImplementation 'com.huawei.hms:hianalytics:5.0.0.301'  googleImplementation 'com.google.firebase:firebase-analytics:17.2.3'}

  1. В DI биндим для типа Analytics экземпляр класса AnalyticsImpl. Сам же AnalyticsImpl у нас будет в двух вариантах. Один в папке src/huawei/kotlin/com/example и выглядеть так:

class AnalyticsImpl(context: Context) : Analytics {    private val analytics = HiAnalytics.getInstance(context)    override fun send(event: AnalyticsEvent) {        analytics.onEvent(event.key, event.data.toBundle())    }}

Другой в папке src/google/kotlin/com/example:


class AnalyticsImpl(context: Context) : Analytics {  private val firebaseAnalytics = FirebaseAnalytics.getInstance(context)  override fun send(event: AnalyticsEvent) {      firebaseAnalytics.logEvent(event.key, event.data.toBundle())  }}

Вот собственно и всё с аналитикой. API библиотек очень похожи и никаких проблем не возникает.


Проверяем, что всё работает


Также, очень удобно можно проверить, что Huawei аналитика работает. Для этого надо:


  1. Подсоединить девайс к компьютеру.
  2. Выполнить в консоли adb shell setprop debug.huawei.hms.analytics.app ТУТ_APPLICATION_ID_ВАШЕГО_ПРИЛОЖЕНИЯ
  3. Открыть консоль разработчика в браузере, перейти в AppGallery Connect -> Мои приложения -> Выбрать приложение -> Раздел "Разработка" -> Управление -> Отладка приложения.
  4. Теперь отправленные из приложения события вы будете видеть в реальном времени прямо на сайте.
  5. Чтобы отключить режим отладки выполните adb shell setprop debug.huawei.hms.analytics.app .none.

Вот так режим отладки выглядит в браузере:


image


Дальше геолокация


С аналитикой мы разобрались, в следующей статье покажем как встроить определение геолокации от Huawei в приложение, которое уже использует аналог от Google.


Весь код, который есть в этом цикле статей вы можете посмотреть в репозитории на GitHub. Вот ссылка.

Подробнее..

Жизнь без AppStore и Google Play работаем с Huawei Mobile Services и AppGallery

07.04.2021 16:22:59 | Автор: admin

С конца 2019 Huawei поставляет Android-смартфоны без сервисов Google, в том числе без привычного всем магазина приложений Google Play. В качестве альтернативы китайская компания предлагает собственные разработки Huawei Mobile Services (HMS), а также магазин AppGallery. В этом тексте я разработчик Технократии Алина Саетова расскажу, как с этим жить и работать.

В статье мы рассмотрим:

  • начало работы c Huawei-системой

  • внедрение Huawei Mobile Services в приложение

  • отладка и тестирование на удаленных устройствах Huawei

  • публикация в AppGallery

Видеоверсию статьи смотрите здесь на канале Технократии.

С чего начать?

Чтобы взаимодействовать с Huawei-системой, нужно завести Huawei ID. Это аналог google-аккаунта, с помощью которого предоставляется доступ к сервисам системы. Далее нужно зарегистрировать аккаунт разработчика: индивидуальный или корпоративный.

  • Индивидуальному разработчику нужно ввести свои ФИО, адрес, телефон, почту. В отличие от регистрации аккаунта разработчика в Google Play, нужны также сканы паспорта и банковской карты. Да-да, документы требуются для удостоверения личности. Huawei обещает удалить их после регистрации.

  • Для регистрации корпоративного аккаунта требуются данные компании, либо DUNS number (международный идентификатор юридических лиц), либо бизнес лицензия.

Ждем одобрения аккаунта. За 1-2 дня Huawei обещают проверить наши данные. После этого можно подключать приложение к HMS. Для этого заходим в консоль AppGallery Connect.

  1. Создаем проект, а в нем добавляем приложение

Обращаем внимание, что для приложения, в котором используются HMS, название пакета должно оканчиваться на .huawei.

2.Помещаем конфигурационный файл agconnect-services.json в корневую папку приложения. Также сохраняем хэш SHA-256. Он потребуется для аутентификации приложения, когда оно попытается получить доступ к службам HMS Core.

Примечание. Для того, чтобы получить SHA-256, можно выполнить команду в терминале, подставив необходимые данные из вашего keystore:

keytool -list -v -keystore <keystore path> -alias <key alias> -storepass <store password> -keypass <key password>

Для работы некоторых сервисов нужно указать место хранения данных:

3.Добавляем зависимости в проект Android Studio.В build.gradle на уровне проекта:

buildscript {      repositories {          google()          jcenter()          maven { url 'https://developer.huawei.com/repo/' }      }      dependencies {      ....        classpath 'com.huawei.agconnect:agcp:1.4.2.301'     }  }allprojects {      repositories {          google()          jcenter()          maven {url 'https://developer.huawei.com/repo/'}      }  }

В build.gradle в модуле app:

apply plugin: 'com.android.application'apply plugin: 'kotlin-android'apply plugin: 'kotlin-android-extensions'apply plugin: 'kotlin-kapt'...apply plugin: 'com.huawei.agconnect'android {...}dependencies {...implementation "com.huawei.agconnect:agconnect-core:1.4.1.300...}

4.Для предотвращения обфускации AppGallery Connect сервисов, Huawei рекомендует прописать следующие правила в файле proguard-rules.pro на уровне модуля app:

  • Для ProGuard:

-ignorewarnings -keep class com.huawei.agconnect.**{*;}
  • Для DexGuard:

-ignorewarnings-keep class com.huawei.agconnect.** {*;} -keepresourcexmlelements ** -keepresources */*

Первоначальная настройка проекта с Huawei Mobile Services завершена.

Внедряем HMS сервисы в проект

Почти на каждый сервис Google у Huawei есть альтернатива:

  • Push Kit. Отправка пуш-уведомлений пользователям.

  • Auth Service. В дополнение к привычным способам аутентификации здесь присутствует вход по Huawei ID.

  • Crash Service. Cервис для отслеживания крашей приложения.

  • Cloud Storage, Cloud DB. Хранение различных файлов и база данных.

  • Location Kit. Получение местоположения пользователя.

  • Analytics Kit. Анализ статистических данных приложения.

  • In-App Purchases. Совершение покупок в приложении.

  • Cloud Testing, Cloud Debugging. Тестирование приложений на удаленных устройствах Huawei.

Этот список можно продолжать долго у Huawei довольно обширный перечень сервисов. Как же подключить их в наш проект?

Прежде всего, нам нужно определиться, как мы будем внедрять сервисы. Есть несколько вариантов:

  • Полностью заменяем GMS сервисы на HMS сервисы

  • Делаем комбинацию GMS и HMS сервисов в одном проекте

В этом деле нам пригодится плагин HMS Toolkit. Он поможет интегрировать HMS Core с минимальными затратами и высокой эффективностью. К сожалению, HMS Toolkit поддерживает конвертацию не всех сервисов, и лучше заранее уточнить, сможет ли он перенести работу ваших.

Нам нужен инструмент Convertor. Он проанализирует проект на наличие GMS сервисов и покажет места, где требуется заменить код с GMS на HMS.

  1. В меню выбираем HMS > Convertor > New Conversion:

2.В появившемся окошке указываем директорию, где создастся бэкап проекта до конвертации.

3.Здесь плагин представляет результаты анализа проекта: какие GMS сервисы у нас содержатся и какие из них конвертируемые. Также нам предлагается проверить sdk version для соответствия требованиям HMS.

На этом шаге мы должны выбрать стратегию конвертации:

  • Add HMS API. На основе существующих в проекте GMS APIs генерируется XMS adapter (как дополнительный модуль в проекте). Он представляет собой прослойку между нашим кодом и непосредственно вызовом сервисов. Это такие Extension-классы, в которых лежит код, поддерживающий HMS и GMS сервисы одновременно. В runtime определяется поддерживаемый девайсом вид сервисов и вызываются соответствующие методы.

  • To HMS API полностью заменяются GMS APIs на HMS APIs.

4.После анализа проекта, мы видим список мест в коде, где необходима конвертация.

По клику на каждый пункт произойдет навигация в файл, где будет предложена конвертация:

Если был выбран способ Add HMS API, мы можем посмотреть на сгенерированный xms адаптер. Вот так, например, выглядит метод из класса ExtensionUser:

А вот размер xms адаптер модуля при использовании лишь одного API с аутентификацией пользователя:

По итогу, APK нашего приложения увеличивается (old size - это APK приложения с only GMS, new size - APK с GMS и HMS одновременно):

Не сказать, что разница велика, но если в приложении будет использоваться несколько API?

Подводные камни

В политике Google Play есть замечание:

Any existing app that is currently using an alternative billing system will need to remove it to comply with this update. For those apps, we are offering an extended grace period until September 30, 2021 to make any required changes. New apps submitted after January 20, 2021 will need to be in compliance.

Что это значит для нас? Теперь, если приложение одновременно поддерживает HMS и GMS сервисы, и в нем есть In-App Purchases, то Google Play не допустит его публикации, а существующим приложениям придется удалить этот функционал.В итоге, если был выбран первый способ конвертации (Add HMS API), мы имеем:

  • Большое количество сгенерированных классов.

  • Увеличенный размер APK приложения.

  • Невозможность публикации приложения в Google Play, если в нем есть In-App Purchases.

  • Неполную поддержку одновременной работы HMS & GMS для некоторых сервисов.

Решение: Более привлекательным вариантом кажется второй способ конвертации простая замена GMS APIs на HMS APIs. Но вместе с этим используем product flavors, чтобы получать сборки приложения отдельно для Google Play и AppGallery.

Product Flavors

Создадим два product flavor - hms и gms:

  • Общий код будет располагаться в директории main/

  • Укажем sourceSets в файлах build.gradle модулей (только там, где необходимо разделение на hms и gms)

  • Код с GMS имплементацией будет в папке gms/, а с HMS соответственно в hms/

  • У hms flavora указываем applicationIdSuffix = .huawei

  • Если же нет необходимости заводить целые файлы отдельно для каждого flavora, то можно проверять текущий flavor через BuildConfig.FLAVOR

android {        flavorDimensions 'services'    productFlavors {        hms {            dimension 'services'            applicationIdSuffix '.huawei'        }        gms {            dimension 'services'        }    }}

По умолчанию, Android Studio заводит sourceSet main, в котором содержатся общие файлы с кодом. Создаем папки для каждого flavora:

New -> Folder -> Выбираем нужный тип папки:

Затем в build.gradle того модуля, где мы создали папку, должен автоматически вставиться следующий код (например, если мы выбрали hms):

android {        productFlavors {        ...    }    sourceSets {        hms {            java {                srcDirs 'src/hms/java'            }            ...        }    }}

Теперь Gradle будет включать в сборку файлы, соответствующие выбранному flavorу. Важно, чтобы файлы в этих директориях имели одинаковое название и лежали в пакетах с одним и тем же названием.

Пример. Мы используем Auth API. У нас будет абстракция интерфейс AuthRepository, хранящийся в main/, а его имплементации для разных сервисов лежат в gms/ и hms/ директориях тогда в сборку, например, для HMS, попадет именно имплементация с huawei сервисами.

Если проект многомодульный, то в каждом модуле необходимо прописать flavorы и при необходимости source sets. Код с flavorами можно вынести в отдельный файл.

Создадем .gradle файл в корневой папке проекта, назовем его flavors.gradle:

ext.flavorConfig = {    flavorDimensions 'services'    productFlavors {        hms {            dimension 'services'            ext.mApplicationIdSuffix = '.huawei'        }        gms {            dimension 'services'        }    }    productFlavors.all { flavor ->        if (flavor.hasProperty('mApplicationIdSuffix') && isApplicationProject()) {            flavor.applicationIdSuffix = flavor.mApplicationIdSuffix        }    }}def isApplicationProject() {    return     project.android.class.simpleName.startsWith('BaseAppModuleExtension')}

Помимо самих flavorов, в экстеншене flavorConfig лежит код с циклом по flavorам там будет определяться app модуль, которому присваивается applicationIdSuffix.

Затем в каждом модуле прописываем следующее:

apply from: "../flavors.gradle"android {    buildTypes {        ...    }    ...    with flavorConfig}

Для использования подходящих плагинов во время процесса компиляции можем добавлять такие if-else конструкции:

apply plugin: 'kotlin-kapt'...if(getGradle().getStartParameter().getTaskNames().toString().toLowerCase().contains("hms")) {    apply plugin: 'com.huawei.agconnect'} else {    apply plugin: 'com.google.gms.google-services'    apply plugin: 'com.google.firebase.crashlytics'}...

Для каждого flavorа мы можем включать dependencies, необходимые только ему. Перед implementation прописываем его название:

// FirebasegmsImplementation platform('com.google.firebase:firebase-bom:26.1.0')gmsImplementation 'com.google.firebase:firebase-crashlytics-ktx'gmsImplementation 'com.google.firebase:firebase-analytics-ktx'// Huawei serviceshmsImplementation 'com.huawei.agconnect:agconnect-core:1.4.2.300'hmsImplementation 'com.huawei.hms:push:5.0.4.302'hmsImplementation 'com.huawei.hms:hwid:5.0.3.301'

Тестируем и отлаживаем приложение

После того, как мы внедрили Huawei сервисы в приложение, нам нужно протестировать его работоспособность.

У Huawei есть облачная платформа DigiX Lab, в которой представлены 2 сервиса.

С помощью сервиса облачного тестирования проверяем совместимость, стабильность, производительность и энергопотребление приложения на удаленных устройствах Huawei. Краткое описание тестов можно увидеть на картинке.

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

Тесты можно запускать либо с помощью плагина в Android Studio:

Либо в консоли AppGallery, выгрузив туда свой APK:

Служба облачной отладки решает проблему отсутствия реальных устройств Huawei. Предоставляется список удаленных устройств, а разовый сеанс работы до 2 часов. Сервис дает 24 часа работы бесплатно после подтверждения личности. Можно подавать заявки на продление срока действия неограниченное количество раз. Отладка также доступна из Android Studio и консоли.

Публикуем приложение в AppGallery

После внедрения сервисов и успешного тестирования приложения, мы готовы публиковаться в AppGallery.

1.Переходим в AppGallery Connect и заполняем данные:

2.Грузим иконку приложения и скриншоты. Есть возможность прикрепить видео.

3.Указываем страны/регионы для публикации и грузим APK приложения. Кроме того, нужно загрузить подпись приложения.

4.Отмечаем способ покупок в приложении и рейтинг.

5.Грузим политику конфиденциальности (обязательно) и предоставляем данные тестового аккаунта, если это необходимо. Указываем дату публикации.

6.Нажимаем кнопочку Отправить на проверку и ждем! Проверка по регламенту занимает около 3-5 дней.

Основные причины отказа в публикации

  1. Политика конфиденциальности не соответствует стандарту

    • Отсутствует ссылка на политику конфиденциальности.

    • Ссылка на политику конфиденциальности недоступна.

    • Ссылка на политику конфиденциальности ведет на официальный сайт компании, на котором нет ссылки на политику конфиденциальности.

  2. Указанный статус Гонконга и Макао не соответствует стандарту.Гонконг и Макао не могут быть указаны как страны на странице выбора региона. Китай очень трепетно относится к этому. Пример:

3.Приведены ссылки на сторонние магазины приложений

Функция для оценки и написания отзыва в приложении содержит ссылку на сторонние магазины приложений без ссылки на AppGallery

Итоги

Huawei выстроили удобный процесс адаптации приложения под свои сервисы. Максимально безболезненный переход к HMS, тестирование и отладка на удаленных устройствах, а также знакомый процесс публикации приложения значительно облегчат жизнь разработчику. И пока что в AppGallery не такая серьезная конкуренция как в других магазинах приложений, самое время присоединяться к Huawei сообществу.

Полезные ссылки

Подписывайтесь на наш Telegram-канал Голос Технократии, где мы пишем о новостях из мира ИТ и высказываем свое мнение о важных событиях.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru