You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

裸React Native中rnmapbox离线包加载报错:需先调用Mapbox.getInstance

解决Mapbox离线包加载失败及"未初始化"报错问题

核心问题分析

报错Using MapView requires calling Mapbox.getInstance(Context context, String apiKey) before inflating or creating the view的本质是Mapbox SDK未完成API密钥初始化——不管是在线地图还是离线包功能,都必须先完成这一步初始化,才能调用MapView或offlineManager相关API。

具体修复步骤

1. 在组件挂载时初始化Mapbox API密钥

在你的Map组件中,添加初始化逻辑,确保在渲染MapView或调用离线包操作前完成密钥设置,可通过useEffect实现:

useEffect(() => {
  // 替换为你的Mapbox API密钥
  Mapbox.setAccessToken('pk.xxxxxxxxx');
}, []);

2. (可选)添加初始化状态控制按钮可用性

避免用户在初始化完成前触发离线包操作,可增加状态控制按钮禁用状态:

const [isMapboxReady, setIsMapboxReady] = useState(false);

useEffect(() => {
  Mapbox.setAccessToken('pk.xxxxxxxxx');
  setIsMapboxReady(true);
}, []);

之后给所有离线操作按钮添加disabled={!isMapboxReady}属性。

3. 完整修改后的组件代码

import React, { useEffect, useState } from "react";
import { StyleSheet, Button, Dimensions, TextInput } from "react-native";
import Mapbox, { Camera, MapView, offlineManager } from "@rnmapbox/maps";
import geoViewport from "@mapbox/geo-viewport";

import Page from "../components/UI/Page";

import { GlobalStyles } from "../constants/styles";
const CENTER_COORD = [-73.970895, 40.723279];
const MAPBOX_VECTOR_TILE_SIZE = 512;

function Map(props) {
  const [packName, setPackName] = useState("pack-1");
  const [showEditTitle, setShowEditTitle] = useState(false);
  const [isMapboxReady, setIsMapboxReady] = useState(false);

  useEffect(() => {
    // 替换为你的Mapbox API密钥
    Mapbox.setAccessToken('pk.xxxxxxxxx');
    setIsMapboxReady(true);
  }, []);

  return (
    <Page {...props}>
      <Button
        title={`Pack name: ${packName}`}
        onPress={() => {
          setShowEditTitle(!showEditTitle);
        }}
      />
      {showEditTitle && (
        <TextInput
          value={packName}
          autoFocus={true}
          onChangeText={(text) => setPackName(text)}
          onBlur={() => setShowEditTitle(false)}
        />
      )}
      <Button
        title="Get all packs"
        disabled={!isMapboxReady}
        onPress={async () => {
          const packs = await offlineManager.getPacks();
          console.log("=> packs:", packs);
          packs.forEach((pack) => {
            console.log(
              "pack:",
              pack,
              "name:",
              pack.name,
              "bounds:",
              pack?.bounds,
              "metadata:",
              pack?.metadata
            );
          });
        }}
      />
      <Button
        title="Get pack"
        disabled={!isMapboxReady}
        onPress={async () => {
          try {
            const pack = await offlineManager.getPack(packName);
            if (pack) {
              console.log(
                "pack:",
                pack,
                "name:",
                pack.name,
                "bounds:",
                pack?.bounds,
                "metadata:",
                pack?.metadata
              );
              console.log("=> status", await pack?.status());
            } else {
              console.log("未找到对应名称的离线包");
            }
          } catch (err) {
            console.error("获取离线包失败:", err);
          }
        }}
      />
      <Button
        title="Resume pack"
        disabled={!isMapboxReady}
        onPress={async () => {
          try {
            const pack = await offlineManager.getPack(packName);
            if (pack) {
              await pack.resume();
            }
          } catch (err) {
            console.error("恢复离线包失败:", err);
          }
        }}
      />
      <Button
        title="Create Pack"
        disabled={!isMapboxReady}
        onPress={() => {
          const { width, height } = Dimensions.get("window");
          const bounds = geoViewport.bounds(
            CENTER_COORD,
            12,
            [width, height],
            MAPBOX_VECTOR_TILE_SIZE
          );

          const options = {
            name: packName,
            styleURL: Mapbox.StyleURL.Street,
            bounds: [
              [bounds[0], bounds[1]],
              [bounds[2], bounds[3]],
            ],
            minZoom: 10,
            maxZoom: 20,
            metadata: {
              whatIsThat: "foo",
            },
          };
          offlineManager.createPack(options, (region, status) => {
            console.log(
              "=> 下载进度:",
              status.completedResourceCount,
              "/",
              status.requiredResourceCount
            );
            if (status.completedResourceCount === status.requiredResourceCount) {
              console.log("离线包下载完成");
            }
          });
        }}
      />
      {isMapboxReady && (
        <MapView style={{ flex: 1 }}>
          <Camera zoomLevel={10} centerCoordinate={CENTER_COORD} />
        </MapView>
      )}
    </Page>
  );
}

额外注意事项

  • API密钥权限检查:确保你的Mapbox API密钥在控制台中开启了DOWNLOADS:READ和DOWNLOADS:WRITE权限,否则离线包创建/读取会失败。
  • 等待离线包下载完成:点击「Create Pack」后,要等回调中显示下载完成(completedResourceCount === requiredResourceCount),再断开网络测试离线功能。
  • 平台配置验证:
    • Android:确保AndroidManifest.xml中添加了网络、存储权限;
    • iOS:确保Info.plist中配置了地图相关权限描述。

内容的提问来源于stack exchange,提问作者coloraday

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 14:54:55