volga-volga / react-native-yamap

React Native Yandex Maps | Яндекс Карты | Yandex.MapKit implementation for react native | YandexMaps
152 stars 85 forks source link

TypeError: null is not an object (evaluating 'NativeYamapModule.init') #209

Closed Fn4ch closed 1 year ago

Fn4ch commented 1 year ago

Работаю с expo, в чём может быть проблема ?

Fn4ch commented 1 year ago

image

aavoronov commented 1 year ago

Та же проблема. Я так догадываюсь, что проблема в самом факте, что мы используем expo. А что делать, я не знаю, это мой первый опыт попытки что-то сделать вне экспо. Документация экспо тоже ясности не вносит: eject вроде как уже deprecated?

aavoronov commented 1 year ago

Работаю с expo, в чём может быть проблема ?

В общем, я попробовал запустить приложение при помощи npx react-native start + npx react-native run-adnroid, инициализировал карты в корневом файле, обернув метод init в useEffect, и вроде заработало. Вместо карты пустая сетка, но это уже что-то

Fn4ch commented 1 year ago

Работаю с expo, в чём может быть проблема ?

В общем, я попробовал запустить приложение при помощи npx react-native start + npx react-native run-adnroid, инициализировал карты в корневом файле, обернув метод init в useEffect, и вроде заработало. Вместо карты пустая сетка, но это уже что-то

Решил проблему создав приложение на react-native-cli Проблема была из-за нативных модулей, в экспо с ними что-то не так

justblender commented 1 year ago

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

Могу предположить, что вы использовали Expo Go для отладки приложения. Он не содержит нативного кода этой библиотеки, из-за чего и выскакивает эта ошибка. Используйте expo prebuild для решения этой проблемы: он производит eject под капотом, генерирует привычные папки android и ios с нативным кодом и позволяет использовать любую библиотеку так же, как и ванильный React Native.

Однако, для корректной работы на iOS react-native-yamap требует обновить AppDelegate.mm и инициализировать YMKMapKit при запуске приложения. prebuild не гарантирует сохранности папок android и ios, их даже нет смысла включать в Git, поэтому напрямую менять нативный код нет смысла - для этого придумали config plugins.

Обновите app.json на app.config.ts и используйте этот пример модификации AppDelegate:

import { type ExpoConfig } from "@expo/config-types";
import { withAppDelegate, type ConfigPlugin } from "expo/config-plugins";

const config: ExpoConfig = {
  name: "Example",
  slug: "example-app",
  version: "1.0.0",
  extra: {
    mapKitApiKey: "bla-bla-bla",
  },
};

const withYandexMaps: ConfigPlugin = (config) => {
  return withAppDelegate(config, async (config) => {
    const appDelegate = config.modResults;

    // Add import
    if (!appDelegate.contents.includes("#import <YandexMapsMobile/YMKMapKitFactory.h>")) {
      // Replace the first line with the intercom import
      appDelegate.contents = appDelegate.contents.replace(
        /#import "AppDelegate.h"/g,
        `#import "AppDelegate.h"\n#import <YandexMapsMobile/YMKMapKitFactory.h>`
      );
    }

    const mapKitMethodInvocations = [
      `[YMKMapKit setApiKey:@"${config.extra?.mapKitApiKey}"];`,
      `[YMKMapKit setLocale:@"ru_RU"];`,
      `[YMKMapKit mapKit];`,
    ]
      .map((line) => `\t${line}`)
      .join("\n");

    // Add invocation
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    if (!appDelegate.contents.includes(mapKitMethodInvocations)) {
      appDelegate.contents = appDelegate.contents.replace(
        /\s+return YES;/g,
        `\n\n${mapKitMethodInvocations}\n\n\treturn YES;`
      );
    }

    return config;
  });
};

export default withYandexMaps(config);
ownikss commented 1 year ago

Спасибо. Добавил эту инструкцию в Readme

jalolov08 commented 3 months ago

Did expo prebuild updated app.config.ts but still error.Target OS Android

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

Могу предположить, что вы использовали Expo Go для отладки приложения. Он не содержит нативного кода этой библиотеки, из-за чего и выскакивает эта ошибка. Используйте expo prebuild для решения этой проблемы: он производит eject под капотом, генерирует привычные папки android и ios с нативным кодом и позволяет использовать любую библиотеку так же, как и ванильный React Native.

Однако, для корректной работы на iOS react-native-yamap требует обновить AppDelegate.mm и инициализировать YMKMapKit при запуске приложения. prebuild не гарантирует сохранности папок android и ios, их даже нет смысла включать в Git, поэтому напрямую менять нативный код нет смысла - для этого придумали config plugins.

Обновите app.json на app.config.ts и используйте этот пример модификации AppDelegate:

import { type ExpoConfig } from "@expo/config-types";
import { withAppDelegate, type ConfigPlugin } from "expo/config-plugins";

const config: ExpoConfig = {
  name: "Example",
  slug: "example-app",
  version: "1.0.0",
  extra: {
    mapKitApiKey: "bla-bla-bla",
  },
};

const withYandexMaps: ConfigPlugin = (config) => {
  return withAppDelegate(config, async (config) => {
    const appDelegate = config.modResults;

    // Add import
    if (!appDelegate.contents.includes("#import <YandexMapsMobile/YMKMapKitFactory.h>")) {
      // Replace the first line with the intercom import
      appDelegate.contents = appDelegate.contents.replace(
        /#import "AppDelegate.h"/g,
        `#import "AppDelegate.h"\n#import <YandexMapsMobile/YMKMapKitFactory.h>`
      );
    }

    const mapKitMethodInvocations = [
      `[YMKMapKit setApiKey:@"${config.extra?.mapKitApiKey}"];`,
      `[YMKMapKit setLocale:@"ru_RU"];`,
      `[YMKMapKit mapKit];`,
    ]
      .map((line) => `\t${line}`)
      .join("\n");

    // Add invocation
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    if (!appDelegate.contents.includes(mapKitMethodInvocations)) {
      appDelegate.contents = appDelegate.contents.replace(
        /\s+return YES;/g,
        `\n\n${mapKitMethodInvocations}\n\n\treturn YES;`
      );
    }

    return config;
  });
};

export default withYandexMaps(config);