Привет, Хабр!
Меня зовут Энрике, и я работаю Go-разработчиком в RuStore. Сегодня хочу рассказать про библиотеку на Go для комфортной работы с API магазина приложений RuStore.
Иногда авторизация через API и получение JWE-токена занимают больше времени, чем хотелось бы. С нашей новой библиотекой процесс становится намного проще — интегрируйте её в свой проект и используйте любые методы RuStore API.
В этой статье мы опишем небольшой пример использования методов из нашей библиотеки: как получить данные по платежу, загрузить APK/AAB-файл и оставить ответ на отзыв пользователя. Все доступные методы можно посмотреть в документации.
Как устроена библиотека
Библиотеку было решено писать на Go, так как этот язык достаточно прост в использовании и удобен для написания HTTP-запросов.
Библиотека RuStore API состоит из следующих директорий:
client
: определяет структуру Client, в которой содержатся все необходимые поля для работы. У Client есть метод Auth(), с помощью которого и происходит авторизация.cmd/examples
: здесь расположены примеры работы с библиотекой.
comments
— работа с отзывами;publishing
— загрузка и публикация приложений;payments
— получение данных платежа и подписки.
Расположенные в корне проекта comments
, payments
, publishing
— пакеты, в которых содержится логика формирования запросов и структура ответов для каждого из разделов RuStore API.
Начало работы
Представим себе, что вы Android-разработчик и планируете опубликовать ваше первое приложение в RuStore. В первую очередь вам нужно зарегистрироваться в RuStore Консоли.
Для использования библиотеки получите всего три параметра из Консоли:
Ваш приватный ключ с разрешениями на работу с нужными разделами;
ID вашего приватного ключа. Его вы получаете при генерации приватного ключа.
Сохраните эти параметры в файле формата JSON (например, options.json) в следующем виде:
{
"companyID":"ID вашей компании",
"privateKeyID":"ID вашего приватного ключа",
"privateKey":"Ваш приватный ключ"
}
Готово! Вы установили параметры, которые будут использоваться при выполнении всех запросов к API.
Авторизация
Авторизуйтесь и передайте параметры из options.json клиенту из пакета client:
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"log"
"net/url"
"os"
"time"
"gitflic.ru/project/rustore/rustoreapi/client"
"gitflic.ru/project/rustore/rustoreapi/publishing"
"gitflic.ru/project/rustore/rustoreapi/comments"
"gitflic.ru/project/rustore/rustoreapi/payments"
)
var (
// так мы парсим все параметры из файла options.json
file = flag.String(
"file",
"",
"file with options: privateKey, privateKeyID, companyID",
)
options Options
)
// структура для того, чтобы сохранить параметры из options.json
type Options struct {
PrivateKey string `json:"privateKey"`
PrivateKeyID string `json:"privateKeyID"`
CompanyID string `json:"companyID"`
}
func main() {
// парсим всё из options.json
flag.Parse()
data, err := os.ReadFile(*file)
if err != nil {
panic(err)
}
if err = json.Unmarshal(data, &options); err != nil {
panic(err)
}
// создаём клиента с переданными из options.json параметрами
cl := client.New(
options.PrivateKeyID,
options.PrivateKey,
options.CompanyID,
)
err = cl.Auth()
if err != nil {
log.Fatal(err)
}
Схематично процесс авторизации выглядит следующим образом:
После авторизации наш JWE-токен будет передаваться в заголовке при каждом вызове метода RuStore API.
Итак, всё самое сложное позади: вы зарегистрировались в Консоли и авторизовались с полученными параметрами.
Загрузка APK-файла
Первое, что нужно сделать, чтобы познакомить пользователей с вашим приложением — загрузить APK-файл.
Чтобы начать работать с методами загрузки и публикации приложений, нужно создать новую сущность (pub в примере), которой вы передадите созданного клиента и packageName вашего приложения.
pub := publishing.New(
cl,
packageName,
)
Таким образом, вы сможете использовать любые методы для загрузки и публикации приложений.
Теперь вам нужно вызвать метод загрузки APK и передать ему необходимые параметры:
var (
//id версии вашего приложения
versionID = 123
// packageName вашего приложения
packageName = "app.example"
// параметры в URL. По умолчанию пустые
urlValues = url.Values{}
// путь к APK, который вы загружаете
fileNameAPK = "Desktop/app-release.apk"
// isMainAPK - признак, который присваивается основному APK-файлу
isMainAPK = true
)
// контекст, который передаётся во все методы
ctx, cancel := context.WithTimeout(
context.Background(),
client.TimeOutSeconds*10*time.Second,
)
defer cancel()
// загружаем APK-файл:
uploadAPK, err := pub.UploadAPKFile(
ctx,
versionID,
fileNameAPK,
isMainAPK,
urlValues,
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\nзагрузили APK файл: %+v\n", uploadAPK)
if uploadAPK.Message != nil {
fmt.Println(*uploadAPK.Message)
}
Вывод:
загрузили APK файл: {Code:OK Message:<nil> Timestamp:2024-03-20 15:31:57.586533733 +0300 MSK}
Вот и всё! Доступ к любому полю ответа вы можете получить с помощью uploadAPK, например:
fmt.Println("Получить код ответа:", uploadAPK.Code)
Вывод:
OK
Вывод, в случае, если есть ошибка (uploadAPK.Message != nil
):
File was not uploaded successfully: The Version Code of the downloaded file must be greater than the previous version
Для запуска программы вы можете воспользоваться командой go run и указать там файл, из которого считываются данные с помощью -file “Имя файла”, например, так:
go run main.go -file options.json
Загрузка AAB файла
В RuStore можно загружать файлы формата не только APK, но и AAB. Порядок действий идентичен загрузке файла APK, за исключением названия метода.
Важно: перед загрузкой AAB файла убедитесь, что у вас загружена подпись для публикации Android App Bundle (AAB) через RuStore Консоль.
uploadAAB, err := pub.UploadAABFile(
ctx,
versionID,
// путь к AAB, который вы загружаете
fileNameAAB,
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\nзагрузили AAB файл: %+v\n", uploadAAB)
if uploadAAB.Message != nil {
fmt.Println(*uploadAAB.Message)
}
Вывод:
загрузили AAB файл: {Code:OK Message:<nil> Timestamp:2024-03-20 15:35:31.486143514 +0300 MSK}
Ответ на отзыв
Итак, файл самого приложения загружен, ваши пользователи начинают реагировать на продукт, и теперь вы хотите отвечать на их отзывы.
Теперь создайте сущность coms, передав в неё клиента и packageName:
coms := comments.New(cl, packageName)
Далее нужно вызвать метод AnswerComment
, передав ID комментария, на который вы хотите ответить, и текст ответа:
var (
// текст, которым вы хотите ответить на отзыв
feedbackText= "Спасибо вам большое!"
// id отзыва, на который вы хотите ответить
commentID = "321"
)
answerComment, err := coms.AnswerComment(
ctx,
commentID,
feedbackText,
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\nответили на отзыв: %+v\n", answerComment)
Вывод:
ответили на отзыв: {Code:OK Message:<nil> Body:{ID:1233211} Timestamp:2024-03-20 16:14:00.06460532 +0300 MSK}
Получение информации о платеже
Вы загрузили приложение, ответили на отзывы, самое время посмотреть информацию по платежам ваших пользователей.
Как и в предыдущих примерах, создайте сущность для работы с платежами:
pay := payments.New(cl, packageName)
Получить информацию о платеже можно с помощью метода GetPaymentInfo
:
Здесь вам понадобится purchaseToken
— связка из userID
и invoiceID
в формате “userID.invoiceID”
.
var purchaseToken = "12345"
paymentInfo, err := pay.GetPaymentInfo(
ctx,
purchaseToken,
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\nИнформация по платежу:%+v\n", paymentInfo)
Вывод:
Информация по платежу:
{Code:OK
Message:<nil>
Body:
{InvoiceID:12345
InvoiceDate:2024-03-04T17:06:40+03
InvoiceStatus:confirmed
ApplicationCode:2414512
ApplicationName:MyApp
OwnerCode:3123124
OwnerName:Иванов Иван Иванович
PaymentInfo:{PaymentDate:2024-03-04T17:07:21+03
PaymentID:123456
PaymentParams:<nil>
LoyaltyInfo:<nil>
CardID: <nil>
PaysysCode:RBS-shortname
MaskedPan:XX1234
ExpiryDate:102313
...
Заключение
Эти и многие другие методы для работы с RuStore API вы можете найти на странице проекта.
Если у вас есть вопросы и предложения по развитию библиотеки, обязательно делитесь ими в комментариях!
Комментарии (5)
milast
29.03.2024 08:48Немного не по теме, но хотел зарегистрироваться в русторе и выложить свое некоммерческое приложение. Но когда дошел до шага верификации, желание подолжить отпало само.
Простите, но отправлять вам фото своего паспорта я не готов. Во-первых - в стравнении с Гуглом (где кстати нет подобной верификации), у вас слишком мало клиентов при меньшей функциональности. Во-вторых - я опасаюсь за свои персональные данные. Сейчас они утекают на лево и направо, кто бы что ни говорил.
Добавить еще один потенциальный источник утечки или передачи третьим лицам моих перс.данных ради публикации частного некоммерческого приложения это неоправдано.
RuStore
29.03.2024 08:48Понимаем ваше беспокойство по поводу защиты личных данных. У нас в RuStore процедура верификации абсолютно конфиденциальна. Мы используем ваши данные только согласно нашей политике конфиденциальности, без каких-либо дополнительных целей.
https://www.rustore.ru/help/legal/privacy-policy-developers/Если у вас всё еще есть вопросы или опасения, пишите нам на support@rustore.ru. Мы можем помочь вам зарегистрироваться без предоставления фотографии паспорта.
micronull
http клиент нельзя подменить в https://gitflic.ru/project/rustore/rustoreapi/blob?file=client%2Fclient.go&branch=master
Сделайте его зависимостью через интерфейс:
Второй момент, это не расширяете контекст ошибки.
Если у вас произойдёт ошибка в
Auth()
то как понять к чему именно она относится?К вызову
GetEncodedSignature
илиGetJWEToken
?Воспользуйтесь:
Дальше смотреть не стал, но вашей библитеке требуется ревью.
EnrikeMorekhon Автор
Спасибо за комментарий!
Обязательно исправим.
micronull
Чтоб не ломать обратную совместимость, подмену http клиента можно сделать через опции.
Так же рекомендую присмотреться к
http.DefaultTransport
для дефолтного http клиента, так как там выставлены таймауты, а у вашего их нет. Это может быть больно)