Перетяжка, Премия ТПрогер, 13.11
Перетяжка, Премия ТПрогер, 13.11
Перетяжка, Премия ТПрогер, 13.11

Как быстро запустить VK Mini Apps на React: гайд для новичков

Vk mini apps. Быстрый старт с React. Как настроить сервер и клиент с vk-bridge.

327 открытий3К показов
Как быстро запустить VK Mini Apps на React: гайд для новичков

Хотите расширить аудиторию своего приложения или игры, интегрировав их прямо в экосистему ВКонтакте? VK Mini Apps — удобный способ создать мини-приложение, которое станет частью социальной сети или даже самостоятельным продуктом внутри нее. Платформа предлагает комфортную среду разработки, обширную документацию и дополнительные бонусы, например, продвижение через каталог.

Я пробовал запускать как приложения, так и игры, и теперь хочу поделиться своим опытом. В этом гайде я расскажу, как быстро разобраться с платформой и библиотекой для VK Mini Apps, чтобы вы могли запустить свой проект без лишних сложностей.

Настраиваем Mini Apps

Для начала регистрируем наше мини-приложение в vk. Разворачиваем с помощью create-react-app или vite, разницы особо не будет.

			npx create-react-app vk-mini-app --template typescript
cd  vk-mini-app
npm start
		

Далее устанавливаем библиотеки от vk. Нам точно понадобится vk-bridge, а остальные не обязательны, но могут подойти для ui.

			npm install @vkontakte/vk-bridge
npm install @vkontakte/vkui @vkontakte/icons
		

Для локальной разработки нам нужно подключить https в package.json без сертификатов.

			"scripts": {
    "start": "PORT=10888 HTTPS=true react-scripts start"
  },
		

Далее указываем локальный адрес, где мы будем разрабатывать приложение. В принципе можно делать это и локально вне платформы, если приложению не требуется общение с vk через мост. Но это довольный редкий кейс. Так что в кабинете разработчика в пункте Размещение вставляем наш айпи адрес и порт выше. Такое проворачиваем для всех типов приложения: десктоп, мобильное приложение, мобильный сайт.

Как быстро запустить VK Mini Apps на React: гайд для новичков 1

Теперь запустим в хроме наш адрес и подтвердим, что мы согласны с угрозой https без сертификата. Далее можем переходить и разрабатывать в самом vk.

Настраиваем Vk bridge

В index.ts инициализируем библиотеку перед рендером приложения.

			bridge.send('VKWebAppInit')
		

Теперь мы можем использовать все события из документации. Например, при старте приложения запрашивать информацию о юзере, используя отдельный хук.

			export const useGetVkUserInfo = () => {
  const dispatch = useDispatch()
  return useCallback(() => {
    (async function () {
      try {
        const user = await bridge.send('VKWebAppGetUserInfo')
        dispatch(profileSliceActions.setVKWebAppGetUserInfo(user))
      } catch (e) {}
    })()
  }, [dispatch])
}
		

Если у вас есть взаимодействие с сервером, то нужно валидировать юзера на сервере с vk параметрами, переданными клиентом, и только потом отдавать jwt token. То есть хранить токены в localStorage запрещено.

На клиенте мы запрашиваем параметры приложения и передаем их на сервер. Так это может выглядеть в саге:

			function* authSignVkBridgeSaga() {
  try {
    const userParams = yield* call(async () => {
      return await bridge.send('VKWebAppGetLaunchParams')
    })
    const ourServerResponse = yield* call(PROFILE_API.authSignVkBridgeAPI, userParams)
    const token = ourServerResponse.token
...
		

На сервере валидируем ответ с помощью функции от vk и нашего секретного ключа из кабинета разработчика. Если все прошло без ошибок — это валидный юзер. Теперь мы можем дальше обмениваться с помощью уже нашего jwt в заголовке, пока юзер не закроет приложение, и тогда повторим все заново.

			/** Верифицирует параметры запуска. */
export function verifyVkBridgeParams(
  searchOrParsedUrlQuery: string | Record
) {
  const secretKey = process.env.VK_SECRET_MINI_APP;
  let sign;
  const queryParams = [];

  const processQueryParam = (key: string, value: unknown) => {
    if (key === "sign") {
      sign = value;
    } else if (key.startsWith("vk_")) {
      queryParams.push({ key, value });
    }
  };

  if (typeof searchOrParsedUrlQuery === "string") {
    // Если строка начинается с вопроса (когда передан window.location.search),
    // его необходимо удалить.
    const formattedSearch = searchOrParsedUrlQuery.startsWith("?")
      ? searchOrParsedUrlQuery.slice(1)
      : searchOrParsedUrlQuery;

    // Пытаемся разобрать строку как query-параметр.
    for (const param of formattedSearch.split("&")) {
      const [key, value] = param.split("=");
      processQueryParam(key, value);
    }
  } else {
    for (const key of Object.keys(searchOrParsedUrlQuery)) {
      const value = searchOrParsedUrlQuery[key];
      processQueryParam(key, value);
    }
  }
  // Обрабатываем исключительный случай, когда не найдена ни подпись в параметрах,
  // ни один параметр, начинающийся с "vk_", чтобы избежать
  // излишней нагрузки, образующейся в процессе работы дальнейшего кода.
  if (!sign || queryParams.length === 0) {
    return false;
  }
  // Снова создаём запрос в виде строки из уже отфильтрованных параметров.
  const queryString = queryParams
    // Сортируем ключи в порядке возрастания.
    .sort((a, b) => a.key.localeCompare(b.key))
    // Воссоздаём новый запрос в виде строки.
    .reduce((acc, { key, value }, idx) => {
      return (
        acc + (idx === 0 ? "" : "&") + `${key}=${encodeURIComponent(value)}`
      );
    }, "");

  // Создаём хеш получившейся строки на основе секретного ключа.
  const paramsHash = crypto
    .createHmac("sha256", secretKey)
    .update(queryString)
    .digest()
    .toString("base64")
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=$/, "");

  return paramsHash === sign;
}
		

Ну вот и вся база для первых шагов с библиотекой. Удачных мини приложений!

Следите за новыми постами
Следите за новыми постами по любимым темам
327 открытий3К показов