This guide contains the steps required to contribute to the development of this project.
This project runs on Apple's Metal rendering framework. Prerequisites for running the test app in simulators:
- macOS 10.15 or later
- Xcode 12.2+
This project requires a valid ~/.netrc file to fetch dependencies.
This project uses SwiftLint to enforce a style guide. Install it with brew install swiftlint
and check for lint by running swiftlint
in the root of the repository.
This project uses secret-shield to help block secrets such as access tokens from being exposed. Install secret-shield
by entering npm install -g @mapbox/secret-shield
. Install the pre-commit hook by running scripts/install-pre-commit/install-pre-commit.sh
Clone the git repository:
git clone git@github.com:mapbox/mapbox-maps-ios.git && cd mapbox-maps-ios
Pre-requisite: Valid .netrc
file located on your machine at ~/.netrc
. Please visit https://docs.mapbox.com/ios/maps/overview for additional information about setting up your .netrc
file.
Open Package.swift
and build the MapboxMaps target.
In order to use the debug app, open Apps/Apps.xcworkspace and build and run the DebugApp
target.
You must provide a Mapbox access token to display Mapbox-hosted maps in the DebugApp
test application. Add your Mapbox token to the MBXAccessToken
key in DebugApp/DebugApp/Info.plist
. Alternatively, create a file at ~/mapbox
containing your access token.
A library is a highly cohesive group of software components that has one responsibility.
For example, annotations should only handle the lifecycle of adding, updating, and removing annotations on a map. It is possible to establish a dependency on other libraries with the exception of MapboxMapsFoundation
library — this library should not depend on any other libraries at any given time, with the exception of the MapboxCoreMaps
library.
To add a new framework as a target within this project, complete the following steps:
- Open
MapboxMaps.xcworkspace
workspace.
-
In the workspace select the
MapboxMaps
project then under the list of targets, select the plus button (+
) to add a new target. In the template view search forFramework
, select it, and then click on Next. On the next dialogue window:- Set the
Product Name
as the name of the framework, prefixed withMapboxMaps
(i.e.,MapboxMapsGestures
,MapboxMapsOrnaments
, etc). - Make sure Swift is selected as the language.
- Make sure
MapboxMaps
is selected as project. - Check the
Include Unit Tests
box. - Make sure
Embed in Application
is set toNone
. - Finally, select Finish.
Additional target configurations are specified with the
Mapbox.xcconfig
andbase.xcconfig
files. Currently these apply to all targets.Please check your build settings for the new target to delete any settings that override the defaults specified in the above
xcconfig
files. For example, you may find that the deployment target is incorrect. - Set the
-
Add your files. Important note: For every new file you add to your target, make sure its target membership is to the framework you've added. In addition, make the file a member of the the
MapboxMaps
target as well.
-
(Optional) If the framework will have a dependency on
MapboxCoreMaps
orMapboxCommon
, perform the following extra steps:- Select the
MapboxMaps
project from the Navigator panel. - Select the framework you just added under Targets.
- Go to the General tab. Under the Frameworks and Libraries section, and add the
MapboxCoreMaps
/MapboxCommon
framework. For the embedding option, chooseDo not embed
.
- Select the
-
For the new framework's associated unit test target, go to the Project Settings for
MapboxMaps
. Under "Configurations", make sure your test target specifies theunitTests
configuration file for debug and release mode. This will ensure test targets are linked properly to other internal frameworks.
Note: Framework tests run on the simulator - they no longer run on device. Instead, please add your Swift test files to the MapboxMapsTests
and MapboxMapsTestsWithHost
targets. These two test targets link against the singular MapboxMaps
framework; MapboxMapsTest
can be used for simulator testing, where MapboxMapsTestsWithHost
will be used for device testing.
-
Add a new step to the
build-all-targets
job:Example:
build-all-targets: <<: *default-job steps: - checkout - run: make deps ... - build-scheme: scheme: MapboxMapsNewFramework
-
Similarly, add a test step to the
maps-unit-tests
job:Example:
# Run the tests in the MapboxTests scheme maps-unit-tests: <<: *default-job steps: - checkout - run: make deps ... - test-scheme: scheme: MapboxMapsNewFramework
Pro tip: CircleCI's YAML format can be picky. You can run make validate
to
ensure you've formatted the changes to the config file correctly. This make target will install the CircleCI command
line interface to validate .circleci/config.yml
, and run circleci config validate
From here, you can add new files to your library and commit these changes to GitHub.
To run device tests there are few options:
-
Run via Xcode: test (Cmd-U) the
MapboxTestsWithHost
scheme. -
Trigger via CI by adding
[run device tests]
to a git commit message. These tests also run "nightly". (Examples can also be run as tests on CI by adding[run app device tests]
.) -
Trigger tests on AWS Device Farm from the command line by running
make test-with-device-farm SCHEME=MapboxMapsTestsWithHost APP_NAME=MapboxTestHost
. This requires certain environment variables to be set; please see the makefile for these. -
Trigger tests on a local device (connected by USB) using the same setup as Device Farm testing by running:
make local-test-with-device-farm-ipa SCHEME=MapboxTestsWithHost CONFIGURATION=Release ENABLE_CODE_SIGNING=1
Integration tests typically test the integration between components. As such most will require a MapView
. These can be run locally and on AWS Device Farm.
Integration tests should be added to the MapboxMapsTests
and MapboxMapsTestsWithHosts
targets. Since these tests require a map view, they also need a UIWindow
and Metal rendering to work. For both testing scenarios, if there's no valid Metal device the test will be skipped (i.e. not failure/success).
There is a host application, so MapViewIntegrationTestCase
fetches the existing window and view controller before adding the MapView to it.
- These tests can be run on devices.
- Tests will be skipped on simulators < iOS 13 because there's no valid Metal device. (iOS 13+ has a simulated Metal device.)
There is no host application, so MapViewIntegrationTestCase
creates its own UIWindow
and root view controller, before adding the MapView to it.
- These tests cannot be run on devices.
- Tests will be skipped on simulators < iOS 13 because there's no valid Metal device.
- Tests will be skipped entirely on CircleCI because of the VM (no Metal). So for CI purposes, integration tests should be run on AWS Device Farm via
MapboxMapsTestsWithHost
As you can see the most useful case is to run within from the host application. Be aware that this has the potential for side-effects, since the application is not restarted for each test.
-
IntegrationTestCase
is a base class that fetches the access token either from the Info.plist or fromUserDefaults
(which will override). The Info.plist inMapboxMaps
has been set up to use the variableMAPBOX_ACCESS_TOKEN
. Please add adeveloper.xcconfig
in the root of the repo, that looks like:MAPBOX_ACCESS_TOKEN = pk.myaccesstoken
The CircleCI config file has been set up to create this.
-
MapViewIntegrationTestCase
subclasses the above, and sets theMapView
, and is theMBXMapViewDelegate
. Closures are used to expose these callbacks to subclasses. Please don't add tests to this class. -
ExampleIntegrationTest
is an example of using the above, that sets a style then waits for the load to finish.
- Check out this doc to get more information about adding examples to our project