> For the complete documentation index, see [llms.txt](https://docs.talsec.app/appsec-articles/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.talsec.app/appsec-articles/articles/shipping-talsec-inside-your-own-sdk-mergeable-ios-frameworks.md).

# Shipping Talsec Inside Your Own SDK: Mergeable iOS Frameworks

**TL;DR:** Talsec's iOS RASP frameworks are now mergeable. If you build an SDK, you can ship Talsec inside it as part of a single framework, so your customers integrate one artifact and nothing else. Debug builds stay dynamic and quick to iterate on, and Release builds produce one optimised binary. You need Xcode 15 or later, Embed & Sign, the right `MERGED_BINARY_TYPE` settings, and a Release-build check before every ship. This article walks through all of it.

<figure><img src="https://1548930415-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNjTFXsqCLQ3RU2oA2uHC%2Fuploads%2FwRhKmxSZ6Z6MXdqGUd0x%2Fimage.png?alt=media&amp;token=6f45b42f-26b8-4bc8-ba12-c4c1a9541338" alt="Shipping Talsec Inside Your Own SDK: Mergeable iOS Frameworks"><figcaption></figcaption></figure>

## The story: one artifact, delivered reliably

Not every Talsec customer ships an app. A growing number ship **SDKs**: payment components, onboarding flows, analytics and fraud-scoring modules, and other building blocks that end up inside other companies' apps. A partner of ours in this space came to us with a clear goal. They wanted Talsec's runtime protection built into their own SDK, so that every app embedding their component would be protected automatically.

Their condition was simple and non-negotiable: **their customers must receive one artifact.** One framework to add, one integration guide, one vendor relationship. Their customers shouldn't have to integrate, configure or even notice a second security SDK.

On iOS, the textbook options don't deliver that. Apple doesn't allow a dynamic framework nested inside another in a shipped app, so the App Store rejects the build. Flattening the frameworks means every customer has to add and Embed & Sign a second framework themselves. Repackaging the SDK in some other ad-hoc way wasn't an option either: whatever we shipped had to keep Talsec's protections working exactly as designed. We weren't willing to trade security for convenience.

Apple's **mergeable libraries** gave us a way to deliver both. That is now how the Talsec iOS frameworks ship.

## How it works: dynamic in Debug, merged in Release

A mergeable framework behaves like a dynamic framework while you develop and like a static one when you ship:

* **Debug.** `TalsecRuntime.framework` stays a separate dynamic image. Incremental builds stay fast, and nothing about your day-to-day workflow changes.
* **Release.** The linker copies Talsec's code into the target that links it: your app, or your own SDK framework. Startup has one less framework to map, and SDK code nothing references can be stripped. The framework bundle stays in the product so its resources and `PrivacyInfo.xcprivacy` are still there.

For SDK vendors this is the key part. When your dynamic framework links `TalsecRuntime` and merges it in Release, Talsec's code becomes part of **your** framework's executable. You ship one binary, and your customer's app embeds only your framework.

The protection code is no longer a separate library image next to the app. It is part of the executable you sign and distribute. The integration API does not change.

## Requirements

These are precise requirements, not suggestions.

* **Xcode 15 or later.** Older linkers do not accept a mergeable framework.
* **Embed & Sign.** Leave the framework on Embed & Sign. **Do Not Embed** drops the bundle, the resources and the privacy manifest, even when the code was merged.
* **`MERGED_BINARY_TYPE` on the linking target.** It decides whether a Release link merges. `automatic` is the usual Release behaviour for an app target. A dynamic framework merges Talsec only if that framework target sets it too. `none` keeps the dynamic layout, and `manual` merges only the frameworks you list.
* **Release builds for verification.** Debug and Release no longer produce the same binary layout. Release links follow static-link rules, so only a Release build shows what actually reaches users.
* **No duplicate third-party symbols.** `TalsecRuntime` contains statically linked third-party dependencies. In Debug they stay inside the Talsec image, so the build succeeds even if your target links the same libraries. A Release merge pulls them into the merging target, and a second copy there stops the link with duplicate symbols that Debug never reported. If you hit this, contact Talsec support and we'll help you resolve it.

A few behaviours to keep in mind:

* The XCFramework you download is larger, because it carries extra link metadata. Merging doesn't raise your minimum deployment target.
* Each target that links the framework is a separate link. An app and an app extension that both link it each get their own copy in Release, and each runs its own static initialization. The same applies to a watchOS app and its extension.
* Crash frames that used to land in the framework binary now land in the executable that merged it. Symbolicate them with the Talsec dSYM shipped beside the XCFramework.

## Setup for SDK vendors: Talsec inside your dynamic framework

Add the built `TalsecRuntime.xcframework` to your framework project. Then, on your dynamic framework target:

* Add `TalsecRuntime.framework` to **Link Binary With Libraries**.
* Copy it into your framework bundle with a Copy Files phase, Destination **Frameworks**, so the product contains `YourFramework.framework/Frameworks/TalsecRuntime.framework`. Debug loads that nested image, and Release still reads resources and `PrivacyInfo.xcprivacy` from it.
* In the **Release** configuration, set `MERGED_BINARY_TYPE` to `automatic`. The Release link copies Talsec's code into your framework binary.
* In the **Debug** configuration, set `MERGED_BINARY_TYPE` to `none`. Debug keeps the nested dynamic image.
* Add `@loader_path/Frameworks` to `LD_RUNPATH_SEARCH_PATHS`, so dyld resolves the nested image from your framework, not from the app.

Your customer's app then gets the single-artifact experience:

* They add your XCFramework and set it to **Embed & Sign** on the app target.
* They do **not** add `TalsecRuntime.xcframework`. The app target doesn't link it, embed it, list it in a runpath or import its module.
* They build against your framework alone. The Talsec bundle travels inside it.

After a Release merge, crash frames from the SDK symbolicate against your framework's dSYM and the Talsec dSYM shipped with the XCFramework.

## CI checklist: what to run before you ship

Run these on every release, in the Xcode version you require in CI:

* [ ] Archive a **Release** build.
* [ ] Launch the app from that archive. Repeat for every app extension and watchOS target that links the framework.
* [ ] If you ship an SDK, repeat the Debug launch and the Release archive in an app project that embeds only your framework.
* [ ] Trigger a code path that uses framework resources, and confirm the privacy manifest is inside `YourFramework.framework/Frameworks/TalsecRuntime.framework` in the IPA.
* [ ] Force a Release link of an app that also embeds the other libraries you ship, and fix any duplicate-symbol errors. Debug will not show them.
* [ ] Symbolicate one crash that falls inside the SDK, and confirm the frame resolves with the shipped dSYM.

## FAQ

<details>

<summary>Does this change the Talsec API?</summary>

No. Your integration code stays the same.

</details>

<details>

<summary>Do app developers who don't build an SDK need to do anything?</summary>

Use Xcode 15 or later, keep Embed & Sign, and verify with a Release build, including the duplicate-symbol check. Your Release app will contain Talsec's code in its executable.

</details>

<details>

<summary>Does merging weaken the protection?</summary>

No. Release builds merge Talsec's code into the executable you sign and distribute, and the protection model stays intact.

</details>

<details>

<summary>Will my customers see Talsec in their project?</summary>

Not as a separate dependency. They embed only your framework, and the Talsec bundle travels inside it.

</details>

<details>

<summary>Why did my Release build fail when Debug worked?</summary>

Most likely duplicate symbols. A Release merge pulls Talsec's statically linked dependencies into the merging target. If something else in that target links the same libraries, the link fails. Debug keeps them inside the Talsec image, so it never shows the conflict.

</details>

<details>

<summary>Does it raise my minimum iOS version?</summary>

No. Merging is a link-time step and does not change your deployment target.

</details>

## Sources

* [Configuring your project to use mergeable libraries (Apple Developer Documentation)](https://developer.apple.com/documentation/xcode/configuring-your-project-to-use-mergeable-libraries)
* [Meet mergeable libraries (WWDC23)](https://developer.apple.com/videos/play/wwdc2023/10268/)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.talsec.app/appsec-articles/articles/shipping-talsec-inside-your-own-sdk-mergeable-ios-frameworks.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
