Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PMTiles URL schema throws error in iOS #618

Open
conbrad opened this issue Jan 15, 2025 · 18 comments · May be fixed by #625
Open

PMTiles URL schema throws error in iOS #618

conbrad opened this issue Jan 15, 2025 · 18 comments · May be fixed by #625

Comments

@conbrad
Copy link

conbrad commented Jan 15, 2025

Describe and reproduce the Bug

iOS uses NSUrl to represent the maplibre tile source. This type doesn't recognize pmtiles://https://<rest-of-url> as a valid url and throws an error:

MapLibre error Requesting: https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles failed with error: Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles, NSErrorFailingURLKey=https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <6816E63E-8AC6-413A-B987-B1B2F8D969DD>.<2>"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <6816E63E-8AC6-413A-B987-B1B2F8D969DD>.<2>, NSUnderlyingError=0x600000d025b0 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}} {"filePath": "-[MLNNetworkConfiguration errorLog:]", "level": "error", "line": 129, "message": "Requesting: https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles failed with error: Error Domain=NSURLErrorDomain Code=-1002 \"unsupported URL\" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles, NSErrorFailingURLKey=https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    \"LocalDataTask <6816E63E-8AC6-413A-B987-B1B2F8D969DD>.<2>\"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <6816E63E-8AC6-413A-B987-B1B2F8D969DD>.<2>, NSUnderlyingError=0x600000d025b0 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 \"(null)\"}}"}

The likely fix is to use a type other than NSUrl to represent the URL for the tile source, perhaps a string or more constrained type.

Repro repo is here: https://github.com/conbrad/pmtiles-ios-bug

@maplibre/maplibre-react-native Version

10.0.0

Which platforms does this occur on?

iOS Simulator, iOS Device

Which frameworks does this occur on?

Expo, React Native

Which architectures does this occur on?

No response

Environment

expo-env-info 1.2.2 environment info:
    System:
      OS: macOS 15.2
      Shell: 3.7.1 - /opt/homebrew/bin/fish
    Binaries:
      Node: 22.12.0 - /usr/local/bin/node
      Yarn: 1.22.22 - /usr/local/bin/yarn
      npm: 10.9.0 - /usr/local/bin/npm
      Watchman: 2024.12.02.00 - /opt/homebrew/bin/watchman
    Managers:
      CocoaPods: 1.14.2 - /Users/cbrady/.rbenv/shims/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 24.2, iOS 18.2, macOS 15.2, tvOS 18.2, visionOS 2.2, watchOS 11.2
    IDEs:
      Android Studio: 2024.2 AI-242.23339.11.2421.12700392
      Xcode: 16.2/16C5032a - /usr/bin/xcodebuild
    npmPackages:
      expo: ~52.0.25 => 52.0.25
      expo-router: ~4.0.16 => 4.0.16
      react: 18.3.1 => 18.3.1
      react-dom: 18.3.1 => 18.3.1
      react-native: 0.76.6 => 0.76.6
      react-native-web: ~0.19.13 => 0.19.13
    Expo Workflow: bare
@conbrad conbrad added the Triage label Jan 15, 2025
@KiwiKilian
Copy link
Collaborator

Is this error only in the logs or is there an actual functional deficit? I've pasted you example in the example app and the borders in BC are rendered.

@conbrad
Copy link
Author

conbrad commented Jan 15, 2025

Is this error only in the logs or is there an actual functional deficit? I've pasted you example in the example app and the borders in BC are rendered.

An actual functional deficit; the app will just crash. Borders render fine in Android. In iOS the problem arises.

Are you running the example repro app in iOS? Simulator or device? I'll admit I only ran this on Android and iOS simulators as I don't have an iOS device, but the error suggests it's problem with NSUrl that likely wouldn't differ on a device.

@KiwiKilian
Copy link
Collaborator

This repository contains two example apps:

  • Expo with new arch
  • Bare React Native with old arch

In both cases it renders fine for me within iOS simulator. I've used this bug report template:

import {
  LineLayer,
  MapView,
  VectorSource,
} from "@maplibre/maplibre-react-native";

export function BugReport() {
  return (
    <MapView style={{ flex: 1 }}>
      <VectorSource
        id="fireCentreSource"
        url="pmtiles://https://nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles"
      >
        <LineLayer
          id="border-fire-centres"
          sourceLayerID="tippecanoe_input"
          style={{ lineColor: "red" }}
        />
      </VectorSource>
    </MapView>
  );
}

Image

@conbrad
Copy link
Author

conbrad commented Jan 15, 2025

This repository contains two example apps:

  • Expo with new arch
  • Bare React Native with old arch

In both cases it renders fine for me within iOS simulator. I've used this bug report template:

import {
LineLayer,
MapView,
VectorSource,
} from "@maplibre/maplibre-react-native";

export function BugReport() {
return (
<MapView style={{ flex: 1 }}>

<LineLayer
id="border-fire-centres"
sourceLayerID="tippecanoe_input"
style={{ lineColor: "red" }}
/>


);
}
Image

I created a simulator for IPhone 16 Pro running iOS 18.2 as you have in your screenshot and it works. Seems like this issue is related to IPhone 15/ iOS 17 and below perhaps. Working on verifying that.

@conbrad
Copy link
Author

conbrad commented Jan 15, 2025

Yes, iPhone 15 running iOS 17 exposes the error:

Image

@KiwiKilian
Copy link
Collaborator

I can also reproduce on iOS 17.5.

@KiwiKilian
Copy link
Collaborator

It might be MapLibre Native needs to fix something here, awaiting feedback. If I just directly pass the NSString the app crashes.

@bdon
Copy link

bdon commented Jan 16, 2025

Would adopting protomaps/PMTiles#509 pmtiles+https:// pmtiles+http:// be a valid short-term solution?

@KiwiKilian
Copy link
Collaborator

@bdon I think that decision is rather on MapLibre Native.

@KiwiKilian
Copy link
Collaborator

KiwiKilian commented Jan 16, 2025

It works on iOS 17 when using a mapStyle like this one https://raw.githubusercontent.com/wipfli/foursquare-os-places-pmtiles/refs/heads/main/style.json.

@KiwiKilian
Copy link
Collaborator

Here are the error logs:

Task <7EEE739C-37EF-4BB2-BF2D-F65AE1153BFF>.<2> finished with error [-1002] Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=https//oliverwipfli.ch/data/v4.pmtiles, NSErrorFailingURLKey=https//oliverwipfli.ch/data/v4.pmtiles, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <7EEE739C-37EF-4BB2-BF2D-F65AE1153BFF>.<2>"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <7EEE739C-37EF-4BB2-BF2D-F65AE1153BFF>.<2>, NSUnderlyingError=0x600000d38f00 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}}
'MapLibre error', 'Requesting: https//oliverwipfli.ch/data/v4.pmtiles failed with error: Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=https//oliverwipfli.ch/data/v4.pmtiles, NSErrorFailingURLKey=https//oliverwipfli.ch/data/v4.pmtiles, _NSURLErrorRelatedURLSessionTaskErrorKey=(\n    "LocalDataTask <7EEE739C-37EF-4BB2-BF2D-F65AE1153BFF>.<2>"\n), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <7EEE739C-37EF-4BB2-BF2D-F65AE1153BFF>.<2>, NSUnderlyingError=0x600000d38f00 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}}', { message: 'Requesting: https//oliverwipfli.ch/data/v4.pmtiles failed with error: Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=https//oliverwipfli.ch/data/v4.pmtiles, NSErrorFailingURLKey=https//oliverwipfli.ch/data/v4.pmtiles, _NSURLErrorRelatedURLSessionTaskErrorKey=(\n    "LocalDataTask <7EEE739C-37EF-4BB2-BF2D-F65AE1153BFF>.<2>"\n), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <7EEE739C-37EF-4BB2-BF2D-F65AE1153BFF>.<2>, NSUnderlyingError=0x600000d38f00 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}}',
  line: 129,
  level: 'error',
  filePath: '-[MLNNetworkConfiguration errorLog:]' }
'MapLibre error', '[event]:Style [code]:-1 [message]:Failed to load source example: Error fetching PMTiles header: unsupported URL', { message: '[event]:Style [code]:-1 [message]:Failed to load source example: Error fetching PMTiles header: unsupported URL',
  line: 30,
  level: 'error',
  filePath: 'virtual bool mbgl::MLNCoreLoggingObserver::onRecord(EventSeverity, Event, int64_t, const std::string &)' }

@KiwiKilian
Copy link
Collaborator

NSURL *url = [NSURL URLWithString:@"pmtiles://https://example.com/some.pmtiles"];
NSLog(@"URL: %@", url.absoluteString);

Logs the following:

  • iOS 17: pmtiles://https//example.com/some.pmtiles (missing :)
  • iOS 18: pmtiles://https://example.com/some.pmtiles

So NSURL differs in the implementation between the two versions.

@conbrad
Copy link
Author

conbrad commented Jan 16, 2025

NSURL *url = [NSURL URLWithString:@"pmtiles://https://example.com/some.pmtiles"];
NSLog(@"URL: %@", url.absoluteString);
Logs the following:

  • iOS 17: pmtiles://https//example.com/some.pmtiles (missing :)
  • iOS 18: pmtiles://https://example.com/some.pmtiles

So NSURL differs in the implementation between the two versions.

Yeah I suspect this is a bug in the NSURL parser in iOS 17, I'm surprised the fix wasn't backported. Is using an NSString crashing when being passed to a function in Maplibre Native?

@KiwiKilian do you have any upstream issues opened you can share?

@conbrad
Copy link
Author

conbrad commented Jan 16, 2025

Would adopting protomaps/PMTiles#509 pmtiles+https:// pmtiles+http:// be a valid short-term solution?

Unfortunately no, I get this error when adjusting trying this alternative:

MapLibre error Requesting: https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles failed with error: Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles, NSErrorFailingURLKey=https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <84A1CE64-F8B6-4B35-979F-61ED02BCCBAB>.<2>"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <84A1CE64-F8B6-4B35-979F-61ED02BCCBAB>.<2>, NSUnderlyingError=0x600000c9b720 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}} {"filePath": "-[MLNNetworkConfiguration errorLog:]", "level": "error", "line": 129, "message": "Requesting: https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles failed with error: Error Domain=NSURLErrorDomain Code=-1002 \"unsupported URL\" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles, NSErrorFailingURLKey=https//nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    \"LocalDataTask <84A1CE64-F8B6-4B35-979F-61ED02BCCBAB>.<2>\"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <84A1CE64-F8B6-4B35-979F-61ED02BCCBAB>.<2>, NSUnderlyingError=0x600000c9b720 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 \"(null)\"}}"}
 (NOBRIDGE) ERROR  MapLibre error [event]:Style [code]:-1 [message]:Failed to load source fireCentreSource: Error fetching PMTiles header: unsupported URL {"filePath": "virtual bool mbgl::MLNCoreLoggingObserver::onRecord(EventSeverity, Event, int64_t, const std::string &)", "level": "error", "line": 30, "message": "[event]:Style [code]:-1 [message]:Failed to load source fireCentreSource: Error fetching PMTiles header: unsupported URL"}

Parser seems to strip off the pmtiles+ prefix and the : in this case.

@bdon
Copy link

bdon commented Jan 17, 2025

I think pmtiles+https:// would require changing the pmtiles implementation in native, but someone ought to check if NSURL parses it correctly in all iOS versions.

@KiwiKilian
Copy link
Collaborator

KiwiKilian commented Jan 17, 2025

I've tested this code and the BugReport example I've posted above:

NSURL *url = [NSURL URLWithString:@"pmtiles://https://example.com/some.pmtiles"];
NSLog(@"%@", url.absoluteString);
NSURL *urlAlternative = [NSURL URLWithString:@"pmtiles+https://example.com/some.pmtiles"];
NSLog(@"%@", urlAlternative.absoluteString);
  • iOS 15.5
  • iOS 16.4
    • Example works
    • pmtiles://https://example.com/some.pmtiles
    • pmtiles+https://example.com/some.pmtiles
  • iOS 17.0 and iOS 17.5 ❌
    • Example is broken due to (URL changed for readability, note the missing :):

      'MapLibre error', 'Requesting: https//example.com/some.pmtiles failed with error: Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL"

    • pmtiles://https//example.com/some.pmtiles ❌ missing :
    • pmtiles+https://example.com/some.pmtiles
  • iOS 18.2
    • Example works
    • pmtiles://https://example.com/some.pmtiles
    • pmtiles+https://example.com/some.pmtiles

Until now I've discussed this on Slack, about to create an issue upstream.

@KiwiKilian
Copy link
Collaborator

KiwiKilian commented Jan 17, 2025

Upstream issue maplibre/maplibre-native#3151. Keeping this open, as we might have to adopt the string constructor, if that's the chosen fix.

@KiwiKilian KiwiKilian linked a pull request Jan 20, 2025 that will close this issue
@KiwiKilian
Copy link
Collaborator

As we wait for the upstream fix release, here is a workaround, which can already be used:

<VectorSource
  id="fireCentreSource"
  tileUrlTemplates={[
    "pmtiles://https://nrs.objectstore.gov.bc.ca/lwzrin/psu/pmtiles/fireCentres.pmtiles",
  ]}
>
  <LineLayer
    id="border-fire-centres"
    sourceLayerID="tippecanoe_input"
    style={{ lineColor: "red" }}
  />
</VectorSource>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants