Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/auto-fix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ on:

jobs:
auto-fix:
if: github.event.label.name == 'agent: create-pr' || github.event_name == 'workflow_dispatch'
if: "${{ github.event.label.name == 'agent: create-pr' || github.event_name == 'workflow_dispatch' }}"
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ secrets.properties

# This covers new IDEs, like Antigravity
.vscode/
.antigravitycli/
build-logic/**/bin/
83 changes: 83 additions & 0 deletions BUILD_KMP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Kotlin Multiplatform (KMP) Maps Demo — Build & Run Guide

This guide details how to build and run the multiplatform Maps Compose library (`:maps-compose-multiplatform`), the Android demo app (`:maps-app`), and the iOS demo app (`iosApp`).

---

## 1. Checkout the PR / Branch

Fetch the remote branch and check it out (or add it as a Git worktree):

```bash
git fetch origin feat/experimental-kmp-module
git checkout feat/experimental-kmp-module
```

*(Alternatively, to isolate your work in a worktree branch)*:
```bash
git worktree add -b feat/experimental-kmp-module feat-experimental-kmp-module origin/feat/experimental-kmp-module
```

---

## 2. Configure Local API Keys

Create a file named `secrets.properties` in the **root** directory of the repository (if you don't already have one) and populate it with your Google Maps API keys:

```properties
MAPS_API_KEY=YOUR_GOOGLE_MAPS_API_KEY
PLACES_API_KEY=YOUR_GOOGLE_PLACES_API_KEY
```

> [!IMPORTANT]
> Both `secrets.properties` and the generated iOS equivalent (`DeveloperSecrets.swift`) are ignored by Git to prevent accidentally leaking credentials.

---

## 3. Building & Running for Android

To compile and verify both the KMP library Android target and the Android sample application (`:maps-app`), run:

```bash
./gradlew assembleDebug
```

---

## 4. Building & Running for iOS (Step-by-Step)

If you are running the iOS project (`iosApp`) for the first time, follow these steps on a Mac with **Xcode** and **CocoaPods** installed:

### Step 4.1: Generate the KMP Dummy Framework
Before CocoaPods can link the local `:maps-compose-multiplatform` podspec, the initial Kotlin framework must exist. From the repository root, execute:

```bash
./gradlew :maps-compose-multiplatform:generateDummyFramework
```

### Step 4.2: Generate the Xcode Project
Navigate to the `iosApp` directory and run the project generation Ruby script (requires the `xcodeproj` gem):

```bash
cd iosApp
ruby create_project.rb
```

> [!NOTE]
> **Build System Output Tracking (Xcode 16+)**: The `create_project.rb` script declares `$(SRCROOT)/iosApp/DeveloperSecrets.swift` as an output of the **Populate Secrets** script build phase. This prevents modern Xcode build systems from failing with `Build input file cannot be found: DeveloperSecrets.swift` during dependency graph analysis.

### Step 4.3: Install Pod Dependencies
Install the required CocoaPods (`GoogleMaps` 10.14.0 and the local KMP library). If your local specs repository is out of date, use the `--repo-update` flag:

```bash
pod install --repo-update
```

### Step 4.4: Open and Run in Xcode
1. Open the generated **Workspace** (do **not** open the `.xcodeproj` file directly):
```bash
open iosApp.xcworkspace
```
2. In Xcode's top toolbar, select the active scheme dropdown and set it to **`iosApp`** (instead of `maps_compose_multiplatform`).
3. Choose an iOS Simulator (e.g., **iPhone 16** or **iPhone 17 Pro**) in the destination dropdown.
4. Click the **Play** button (or press **Cmd + R**) to compile, run the secrets population script, and launch the app!
19 changes: 19 additions & 0 deletions iosApp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# CocoaPods
Pods/
Podfile.lock

# Xcode
build/
DerivedData/
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
xcuserdata/
*.xcworkspace
!default.xcworkspace
*.xcuserstate

# Secrets
iosApp/DeveloperSecrets.swift

11 changes: 11 additions & 0 deletions iosApp/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
platform :ios, '16.0'

# Ignore warnings from CocoaPods dependencies
inhibit_all_warnings!

target 'iosApp' do
use_frameworks!

# Reference our local KMP module via its podspec path
pod 'maps_compose_multiplatform', :path => '../maps-compose-multiplatform'
end
72 changes: 72 additions & 0 deletions iosApp/create_project.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
require 'xcodeproj'

# Initialize project
project_path = 'iosApp.xcodeproj'
project = Xcodeproj::Project.new(project_path)

# Set deployment target to iOS 16.0 project-wide
project.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.0'
end

# Create group for source files (maps to the iosApp directory)
group = project.main_group.new_group('iosApp', 'iosApp')

# Reference source files inside the group
app_delegate_ref = group.new_file('AppDelegate.swift')
sample_list_ref = group.new_file('SampleListViewController.swift')
secrets_ref = group.new_file('DeveloperSecrets.swift')
info_plist_ref = group.new_file('Info.plist')

# Create target
target = project.new_target(:application, 'iosApp', :ios, '16.0')

# Configure target settings
target.build_configurations.each do |config|
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'com.google.maps.android.compose.iosApp'
config.build_settings['INFOPLIST_FILE'] = 'iosApp/Info.plist'
config.build_settings['SWIFT_VERSION'] = '5.0'
config.build_settings['SDKROOT'] = 'iphoneos'
config.build_settings['TARGETED_DEVICE_FAMILY'] = '1,2'
config.build_settings['CODE_SIGNING_REQUIRED'] = 'NO'
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
config.build_settings['AD_HOC_CODE_SIGNING_ALLOWED'] = 'YES'
end

# Add a Build Phase Run Script to populate secrets before compilation
populate_secrets_phase = target.new_shell_script_build_phase('Populate Secrets')
populate_secrets_phase.output_paths = ['$(SRCROOT)/iosApp/DeveloperSecrets.swift']
populate_secrets_phase.shell_script = <<-SHELL
SECRETS_PATH="${PROJECT_DIR}/../secrets.properties"
OUTPUT_FILE="${SRCROOT}/iosApp/DeveloperSecrets.swift"

API_KEY="YOUR_API_KEY"

if [ -f "$SECRETS_PATH" ]; then
EXTRACTED_KEY=$(grep -E "^MAPS_API_KEY=" "$SECRETS_PATH" | cut -d'=' -f2 | tr -d '"' | tr -d "'")
if [ ! -z "$EXTRACTED_KEY" ]; then
API_KEY="$EXTRACTED_KEY"
fi
fi

cat <<EOF > "$OUTPUT_FILE"
// Generated file. Do not commit or modify.
struct DeveloperSecrets {
static let mapsApiKey = "$API_KEY"
}
EOF
SHELL

# Move the secrets phase to the very beginning of target build phases
target.build_phases.delete(populate_secrets_phase)
target.build_phases.insert(0, populate_secrets_phase)

# Add files to their respective build phases
source_build_phase = target.source_build_phase
source_build_phase.add_file_reference(app_delegate_ref)
source_build_phase.add_file_reference(sample_list_ref)
source_build_phase.add_file_reference(secrets_ref)

project.save
puts "Xcode project created successfully!"

Loading
Loading