# linphone-iphone: a SIP softphone for iOS with SwiftPM and MDM provisioning

> Linphone for iOS is a Swift softphone for SIP voice, video, presence and messaging, distributed under GPLv3 or a paid proprietary licence. Since version 6.0 it builds against a Swift Package Manager SDK, and it can be provisioned by MDM with a configuration dictionary, a root CA and a remote configuration URI.

**BelledonneCommunications/linphone-iphone** — Linphone is a free VoIP and video softphone based on the SIP protocol. Mirror of linphone-iphone (git://git.linphone.org/linphone-iphone.git)

- Repository: https://github.com/BelledonneCommunications/linphone-iphone
- Website: http://linphone.org
- Stars: 663 · Forks: 397
- Language: Swift
- License: GPL-3.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/belledonnecommunications-linphone-iphone

## A SIP softphone where calling, presence and IM share one protocol

Linphone is described as an open source softphone for voice and video over IP calling and instant messaging, and the detail that matters is in the second sentence: it is fully SIP-based for all calling, presence and IM features.

That single-protocol statement is the architectural commitment. There is no separate signalling stack for presence and a separate one for messaging, and no proprietary gateway in the middle. The project topics reflect the same shape, listing call, chat, conference, message, phone, video, voip and sip.

Who it is for has two halves. End users get a free SIP client. Developers and IT teams get a source tree they can build, rebrand and provision themselves, which is what the rest of this project is about: an Xcode project, a Swift package SDK, a managed configuration mechanism, an MDM story and a translation platform.

The README points to a general description on the linphone web site, to a features page listing supported features and RFCs, and to the public Linphone wiki. That last link matters for evaluation, because the README itself does not enumerate what the client supports, so the features and RFCs page is where the actual capability list lives.

The repository is a mirror, as the project description says, of linphone-iphone hosted on git.linphone.org.

## Dual licensing means GPLv3 or a paid proprietary agreement

Linphone is dual licensed, and the README explains both branches.

The first is the GNU/GPLv3 licence, which is the free open source option. The README asks you to make sure you understand and agree with the terms of that licence before using it, and points to the LICENSE file for details.

The second is a proprietary licence, for a fee, for use in closed source applications, with a link to contact Belledonne Communications for questions about costs and services.

For a VoIP client, the copyright notice is Belledonne Communications. The practical consequence for an organisation building an app on top of this code is a fork in the road before any code is written. Ship the app closed and you need the commercial licence. Modify and distribute the client itself, and the GPLv3 terms apply.

That is not legal advice, just the shape of the decision. What matters for a technical evaluation is that the licence choice has to be settled early, because it determines whether you can keep your modifications private.

The other licensing-adjacent fact is that translations are contributed, not licensed in bulk, which is covered below.

## Version 6.0 moved the build to Swift Package Manager

The biggest structural change in the project is the dependency model. With Linphone 6.0, the app switched to Swift Package Manager, and by default it uses a remote SPM repository hosted on the project's GitLab:

```bash
https://gitlab.linphone.org/BC/public/linphone-sdk-swift-ios.git
```

To build the app itself, the README says to open linphone.xcodeproj with Xcode, and notes that the remote SPM is already configured in the app. In other words, for most contributors the SDK dependency resolves automatically and the build is an Xcode operation rather than a dependency authoring exercise.

For anyone who needs to work against a local build of the SDK, the README documents the full path. You clone the linphone-sdk repository from the project's GitLab and initialise its submodules:

```bash
git clone git@gitlab.linphone.org:BC/public/linphone-sdk.git
git submodule update --init --recursive
```

Then you build the SDK with a CMake preset:

```bash
cmake --preset=ios-sdk -G Ninja -B spm-ios && cmake --build spm-ios
```

That last command is worth reading twice. The SDK is a CMake project with an iOS preset, the generator is Ninja, and the build directory is spm-ios, which is the same directory name the local package path later refers to. The SDK is therefore built outside Xcode and consumed as a Swift package, which is why the C and Objective-C core can sit underneath a Swift app.

## Adding the package by hand, and the two targets you must attach

Both dependency routes end in the same place in Xcode, and the README walks through it step by step.

You go to the Package Dependencies section of the project. For the remote route, you enter the SDK URI in the top-right corner, change the Dependency Rule to Branch and enter the keyword stable, then click Add Package. A page opens where you add targets to the library, and the README notes that this is normally not necessary because the dependencies on Linphone and msgNotificationService should already be present. After that, you check that the library appears in the Frameworks, Libraries, and Embedded Content section of every target that needs it, adding it manually if needed.

For the local route, the difference is that you click Add Local instead and follow the path yourSdkPath/linphone-sdk/spm-ios/linphone-sdk-swift-ios, which is the output of the CMake build in the previous step.

Two details deserve attention. The Dependency Rule is set to Branch with the keyword stable, so the package tracks a moving branch rather than a pinned version, which is worth remembering when you need reproducible builds. And the two targets, Linphone and msgNotificationService, are not interchangeable, since the second is the push notification service target and the repository layout shows a msgNotificationService/ directory alongside linphoneExtension/ and intentsExtension/.

A missing embedded framework shows up as a runtime failure rather than a build error, so the check in the Frameworks, Libraries, and Embedded Content section is worth doing every time.

## MDM provisioning: xmlConfig, rootCa and configUri

The mechanism that makes Linphone manageable at scale is managed app configuration through the standard iOS MDM com.apple.configuration.managed mechanism. When the app is deployed through an MDM server, administrators push a configuration dictionary that the app reads at startup and whenever the managed configuration changes at runtime.

Three keys are supported, and each one maps to a specific SDK capability.

The xmlConfig key carries a Linphone configuration in XML format, using the same schema as linphonerc, and it is applied through Config.loadFromXmlString. That is how you push a full account and server configuration to managed devices.

The rootCa key is a PEM-encoded root CA certificate used by the Linphone SDK for TLS operations, covering SIPS and HTTPS provisioning, and it is applied to core.rootCaData. It is the key that lets a device trust your internal certificate authority.

The configUri key is a URI for a remote provisioning file. It takes precedence over any config-uri defined inside xmlConfig, and it triggers a core restart so the remote configuration is fetched.

All three keys are optional and can be combined. The README spells out the ordering rule: if configUri is present it is set last and the core is restarted, so a config-uri embedded in xmlConfig is overridden. Applying and removing the configuration at runtime is supported, and removing it resets the core to its default configuration and returns to the assistant and login screen.

For an IT team, that last behaviour is the useful one. Unenrolling a device from MDM returns the app to a clean state without manual intervention.

## UI tests exercise the managed configuration path end to end

Because MDM configuration is the feature most likely to break silently, the project ships tests for it, and the README says two kinds of tests are provided.

The first is UI tests, described as end to end, located in LinphoneAppUITests/MDMChatFeatureUITests.swift. They inject a managed configuration at launch through the app's DEBUG-only mechanism, whose name begins with UITEST_ and is cut off in the visible text.

The repository layout backs up the structure. There is a LinphoneAppTests/ directory for unit tests, a LinphoneAppUITests/ directory for the UI tests, and the project file is LinphoneApp.xcodeproj. There is also a Shared.xcconfig at the root, a .swiftlint.yml for lint rules, a .git-pre-commit hook, a .gitlab-ci.yml for continuous integration, and a GoogleService-Info.plist.

The number of localisations is notable. The tree carries Base.lproj plus ca, cs, de, en, es, eu, fi, fr, hu, mk, nl, pt-BR, pt, ru, sk, uk and zh-Hans, so the app ships in a wide range of languages. That connects to the translation story in the README, which explains that the project no longer uses transifex and now runs its own Weblate instance, and that because of the full app rewrite the previous translations could not be reused, so contributors are welcome to redo them.

## Beta testing through TestFlight, with a defined bug report flow

There are no GitHub releases for this project, and the distribution path the README documents is TestFlight.

The steps it gives are concrete. Download TestFlight from the App Store and log in with your Apple ID, tap the public link on the iOS device, then touch View in TestFlight or Start Testing. You can also touch Accept, Install or Update for the Linphone app, and when a new beta is available you update it with the same public link.

Crash reports are handled by TestFlight itself, automatically, which removes one class of work from the beta process.

Bug reports have a defined route inside the app. You open Linphone, go to Settings, then Advanced, then Send logs. That creates an email to linphone-iphone@belledonne-communications.com with the logs attached. The README asks you to fill in the bug description with what you were doing, what happened, what you were expecting, and approximately when the bug happened, then to change the object line to [Beta test - Bug report] and send it.

The reason for the subject change is obvious once you know about it. Everything in that inbox is a beta report, and the marker lets the team separate them from production support traffic. A small detail, but the difference between a report being triaged and being lost is usually a subject line.

Contributors are pointed to CONTRIBUTING.md and asked to read the README in full first.

## Conclusion

linphone-iphone suits organisations that need SIP calling, presence and messaging on iOS devices under their own control, and it suits IT teams that provision phones through an MDM server rather than by hand. It does not suit a product team that needs to ship a closed source app without a licensing conversation, because the open source build is GPLv3 and the alternative is a paid proprietary licence from Belledonne Communications. Check three things before you start: whether your SIP infrastructure matches the supported features and RFCs listed in the project documentation, whether you can point the app at a remote configuration through MDM, and whether the Xcode project still points at a stable remote package rather than a local build. The last push to the repository was on 2026-10-22 and there are no GitHub releases, so the TestFlight channel is the distribution path the project documents.

## FAQ

### How is Linphone for iOS licensed?

Linphone is dual licensed: under GNU/GPLv3 for free open source use, or under a proprietary licence for a fee for closed source applications, with costs and services handled through Belledonne Communications.

### How do I build linphone-iphone from source?

Open linphone.xcodeproj with Xcode; the remote Swift package dependency is already configured. To use a local SDK instead, clone git@gitlab.linphone.org:BC/public/linphone-sdk.git, run git submodule update --init --recursive, then build with cmake --preset=ios-sdk -G Ninja -B spm-ios && cmake --build spm-ios and add the package as a local dependency.

### Which managed configuration keys does Linphone for iOS support?

Three: xmlConfig, a Linphone configuration in XML applied through Config.loadFromXmlString, rootCa, a PEM-encoded root CA applied to core.rootCaData, and configUri, a remote provisioning URI that overrides any config-uri inside xmlConfig and triggers a core restart.

### How do I get beta builds of the Linphone iOS app?

Through TestFlight: download it from the App Store, sign in with your Apple ID, then open the public TestFlight link on the device and tap View in TestFlight or Start Testing. New betas are installed with the same link.

### How do I report a bug in the Linphone iOS beta?

In the app go to Settings, then Advanced, then Send logs, which prepares an email to linphone-iphone@belledonne-communications.com with the logs attached. Fill in what you were doing, what happened, what you expected and roughly when it happened, and set the subject to [Beta test - Bug report].

## Sources

- [BelledonneCommunications/linphone-iphone on GitHub](https://github.com/BelledonneCommunications/linphone-iphone)
- [Issues](https://github.com/BelledonneCommunications/linphone-iphone/issues)
- [License: GPL-3.0](https://github.com/BelledonneCommunications/linphone-iphone/blob/master/LICENSE)
- [Project website](http://linphone.org)
- [README](https://github.com/BelledonneCommunications/linphone-iphone/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/belledonnecommunications-linphone-iphone
