Skip to main content
ClaudeWave
Skill808 repo starsupdated 3d ago

build-ios-binary

Compile a PAM control's iOS Obj-C/Swift module into the FLAT device-slice `.framework` for a `.ppmplugin` bundle (never an `.xcframework` — the wrap CI won't descend into one). Mac-only (Xcode). Builds from a throwaway staged copy so canonical `ios/` and the podspec stay untouched, references React-Core headers only (React is weak-linked and provided by the wrap host at runtime, no CocoaPods), generates the required umbrella header, module map and Info.plist, sets the critical build settings, asserts manifest conformance, then runs a device-only `xcodebuild archive` and copies out the flat framework to `ppmplugin/staging/ios/`. Known limitation — the React weak-link flags aren't yet validated against a live wrap host and the RN pin must match the host's. Run after /generate-ppmplugin-manifest for an iOS or Both target, before /assemble-ppmplugin.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/microsoft/power-platform-skills /tmp/build-ios-binary && cp -r /tmp/build-ios-binary/plugins/power-apps-mobile-extension/skills/build-ios-binary ~/.claude/skills/build-ios-binary
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# /build-ios-binary

Turns the extension's iOS **source** (`ios/RCT<Pascal>Module.{h,m}`) into the **flat `<Pascal>Plugin.framework/`** (device slice) that the wrap runtime loads. iOS analogue of [`/build-android-binary`](../build-android-binary/SKILL.md): source in, a prebuilt framework out.

> **Ship a FLAT `.framework`, NOT an `.xcframework`.** The wrap pipeline expects `ios/<Name>.framework` and does not descend into an `.xcframework` — shipping one fails with *"Framework '<Name>.framework' not found in plugin."* This skill builds the **device archive only** and copies out the flat `.framework`. See [`ppmplugin-format §5b`](../../shared/ppmplugin-format.md).

> **Mac-only.** Requires Xcode. On Linux/Windows this skill BLOCKs — Android-only contributors can't produce the iOS slice.
>
> **KNOWN LIMITATION — read this.** The single hard part is **React-Core**: the framework compiles against React's headers (`#import <React/RCTBridgeModule.h>`) from the control repo's own pinned `react-native` devDep, while **never embedding React** — the wrap host provides it at runtime (weak-link). The coupling that matters is the **RN version pin** (`0.79.7`): it must match the RN the wrap host ships. The exact weak-link flags / header-search-path setup aren't yet validated against a live wrap host — that's the main risk area. React symbol/header errors mean the RN pin diverged from the host's RN, not a code bug.

Read [`shared/ppmplugin-format.md`](../../shared/ppmplugin-format.md) §5b (iOS binary requirements) and the [`naming-conventions.md`](../../shared/naming-conventions.md) iOS rows.

## What this skill does NOT do
- Does not author `manifest.json` (run [`/generate-ppmplugin-manifest`](../generate-ppmplugin-manifest/SKILL.md) first — this skill reads it for cross-checks and the framework/moduleClass names).
- Does not zip the `.ppmplugin` — that's [`/assemble-ppmplugin`](../assemble-ppmplugin/SKILL.md).
- Does not build Android — that's `/build-android-binary`.
- Does not modify the canonical `ios/` or the podspec — all adjustments live in a throwaway copy under `ppmplugin/staging/ios-build/`.
- Does not sign the framework — the wrap pipeline signs at packaging time (given `BUILD_LIBRARY_FOR_DISTRIBUTION=YES SKIP_INSTALL=NO`). No signing skill needed.

---

## Step 1 — Read shared docs + prereq block

1. Read [`shared/shared-instructions.md`](../../shared/shared-instructions.md) and [`shared/ppmplugin-format.md`](../../shared/ppmplugin-format.md).
2. Read `ppmplugin/staging/manifest.json`. If absent, STOP with `NEEDS_CONTEXT: manifest.json missing — run /generate-ppmplugin-manifest first`. If it has no `entrypoints.ios`, STOP with `NEEDS_CONTEXT: manifest targets Android-only — re-run /generate-ppmplugin-manifest and choose iOS/Both`.
3. Read the `## ppmplugin (third-party controls)` block in `.extension-state.md`. **Replace-existing gate:** if `ppmplugin/staging/ios/<framework>.framework` already exists, surface it (with its build timestamp) and ask via `AskUserQuestion` — **Keep existing** (skip to Step 6) vs **Replace (rebuild)**. Default Keep if source + manifest unchanged since the recorded build, else Replace (note Keep is stale). Per [`ppmplugin-format §1`](../../shared/ppmplugin-format.md) replace-existing rule.
4. Run prereq checks and print the visible block (shared-instructions §9.2). **Policy: resolve, don't punt** (locate tools by path; offer + run safe installs):

| Check | Verify | Auto-fix |
|---|---|---|
| **macOS** | `uname` = Darwin | NOT fixable — STOP with `BLOCKED: /build-ios-binary is Mac-only (iOS needs Xcode)` on Linux/Windows |
| Xcode 16+ (26.2+ recommended) | `xcodebuild -version` | NOT auto-fixable — print: install Xcode from the App Store / xcodes; STOP if missing |
| React-Core headers present | `node_modules/react-native/React/Base/RCTBridgeModule.h` exists (the `react-native` devDep, in the control repo) | if the devDep isn't installed: `pnpm install` in the repo |
| CocoaPods (**optional** — fallback path only) | `pod --version` | Not required for the recommended header-only build (Step 2). Only needed if you fall back to the Podfile path; `brew install cocoapods` on confirm. |

---

## Step 2 — React-Core source (self-contained) + confirm the config

The framework needs React's headers at compile time. **The source is the control repo's own `node_modules/react-native`** — the pinned `react-native` devDep (`0.79.7` for pen-input), which ships the React headers (`React/Base/RCTBridgeModule.h`). The build is fully self-contained in the control repo. If the devDep isn't installed, run `pnpm install`; only if it's genuinely absent, ask the user for a `react-native` path.

**Recommended: header-only React (no CocoaPods).** Aggregate the React headers into a flat include dir in the staging copy and point the framework target at it — cleaner and faster than the Pod chain, and it avoids the CocoaPods/React-Codegen failures that bite under recent Xcode (see [`ppmplugin-format §5b`](../../shared/ppmplugin-format.md)):
```bash
mkdir -p ppmplugin/staging/ios-build/include/React
# copy the RN headers the module imports (Base + the Libraries it uses):
cp node_modules/react-native/React/Base/*.h        ppmplugin/staging/ios-build/include/React/
cp -R node_modules/react-native/React/Base node_modules/react-native/Libraries  ppmplugin/staging/ios-build/include/React/ 2>/dev/null || true
```
Then set on the framework target: `HEADER_SEARCH_PATHS = $(inherited) $(SRCROOT)/include` and `OTHER_LDFLAGS = -undefined dynamic_lookup` (weak-links React's symbols — the host provides them at runtime). **`-undefined dynamic_lookup` is deprecated by Apple** (works today, may break in a future Xcode — known caveat).

**Fallback: CocoaPods** — only if the header-only path doesn't suffice. A Podfile referencing the devDep (`pod 'React-Core', :path => '<repo>/node_modules/react-native'`) gives CocoaPods the header map, but on recent Xcode/RN-0.79 you'll need `post_install` patches (boost URL,
add-data-sourceSkill

Guide the user to add a data source, connection, or API connector to a Canvas App via Power Apps Studio, then verify and continue. USE WHEN the user asks to add a data source, add a connection, add an API, add a connector, connect to SharePoint / Dataverse / SQL / Excel / OneDrive / Teams / Office 365, or any similar request to make new data available to the app. DO NOT USE WHEN the user is asking to list or describe existing data sources — call list_data_sources or list_apis directly instead.

canvas-appSkill

Creates or edits a Power Apps Canvas App through the Canvas Authoring MCP coauthoring session. Handles new app generation, direct targeted edits, complex multi-screen changes, responsive layout, per-screen self-QA, and compile-error convergence. Trigger on requests to create, build, generate, modify, update, change, fix, or edit a Canvas App or .pa.yaml files.

configure-canvas-mcpSkill

Configure the Canvas Authoring MCP server for the current coauthoring session. USE WHEN "configure MCP", "set up MCP server", "MCP not working", "connect Canvas Apps MCP", "canvas-authoring not available", "MCP not configured", "set up canvas apps".

generate-canvas-appSkill

[DEPRECATED — use canvas-app instead] Generate a complete Power Apps canvas app.

report-issueSkill

>

add-azuredevopsSkill

Adds Azure DevOps connector to a Power Apps code app. Use when querying work items, creating bugs, managing pipelines, or making ADO API calls.

add-connectorSkill

Use when adding a Power Platform connector to an Expo/React Native Power Apps mobile app and no dedicated mobile connector skill exists.

add-datasourceSkill

Use when adding an unspecified data source to an Expo/React Native Power Apps mobile app; routes to Dataverse, SharePoint, or another connector.