Post written by Salmaan Ahmed, Program Manager, Windows Bridge for iOS
Today I’m going to take you a bit deeper on what’s in the Windows Bridge for iOS (previously referred to as ‘Project Islandwood’), how it enables iOS developers to bring their code and skills to Windows, and why we’ve decided to make this particular Windows bridge available as open-source on GitHub.
As Kevin Gallo announced this morning, we are releasing an early look at our iOS bridge today, with final release scheduled for this fall. This is very much a work-in-progress and some of the components we showed at Build in April are not ready yet or still in an early state. Today’s release supports building apps that target both Windows 10 and Windows 8.1 built for x86 and x64 processor architectures, and through the fall we’ll add additional capabilities as more of the bridge is being completed.
For those just joining us, the Windows Bridge for iOS is intended to enable iOS developers to create Windows apps using your existing Objective-C code and skills. To accomplish this, this bridge is comprised of four components:
- Objective-C compiler: To enable most of the heavy lifting, Visual Studio will include a compiler that knows how to take Objective-C code and compile it into a native Universal Windows app. For now, we will provide early drops of the compiler binary via GitHub (we’re not open sourcing the compiler). The compiler will ultimately ship as part of a Visual Studio 2015 update scheduled in the fall.
- Objective-C runtime: Additionally, our Objective-C runtime will provide you with language features like message dispatch, delegation and automatic reference counting.
- iOS API headers/libs: Building upon the Objective-C base APIs, we provide fairly broad iOS API compatibility. As you begin working with the bridge, and as you find an API that isn’t yet supported or could be improved, we welcome your contributions and comments.
- Visual Studio IDE integration: Finally, we provide tooling that imports your Xcode project and ties into the Windows developer tools (Visual Studio 2015) and SDK.
At Build, we provided a first look at the bridge in action. Today, I’d like to show off a number of new, exciting features that are available with the release to GitHub.
Why the bridge is not a port
Our goal with the iOS bridge has never been simply to run iOS apps on Windows. Rather, our goal is to help you write great Windows apps that use as much of your existing code and knowledge as possible. We will, of course, continue to work to expand our iOS compatibility, but it’s important to note that there is much more you can do with the bridge.
Behind this goal are three core principles that drove the architecture and design of the bridge:
- Full Windows API access: Making it easy to use Windows APIs within Objective-C code
- iOS compatibility: Empower developers to reuse as much existing iOS code as reasonably possible
- No sandboxing: iOS and Windows APIs should be able to work together
Our first principle is especially important because Windows has a rich and fully functional API set that continues to grow and evolve. If the current release of the bridge doesn’t support a particular feature that you need, then we don’t want you to feel “stuck” until the next update; instead, we’d much rather make it simple for you to use the corresponding Windows API and integrate everything seamlessly into your code.
The third and first principles are thereby linked – the ability to call and use the full Windows API surface would be severely restricted if the API sets were sandboxed from one another, limiting your ability to build good Windows apps in Objective-C. Let’s look closer as to how we ensure this is not the case, both at the code level and in the UI.
When Windows and Objective-C APIs meet
As introduced at Build, the bridge uses a customized complier (clang+cl) to compile Objective-C source code, and the generated object files are then linked together using Microsoft’s linker. This approach is great because it allows Objective-C and C++/CX to “get along” well – they can coexist in the same project and call one another using C or C++ interfaces.
The approach works, but there is a minor complication with it. Because clang doesn’t “understand” the CX extensions (which are needed to call Windows APIs), you’re required to create .cpp files and then manually connect your Objective-C and C++/CX worlds so that you can take full advantage of the Universal Windows Platform (UWP) API set. While this is perfectly doable, we believed that we could do better and this is where “projections” come in.
For those new to projections, Miguel de Icaza does an admirable job of describing on his blog. In short, projections are the Microsoft way of exporting or “projecting” a Windows API to new programming languages. We’ve taken this scheme and used it to enable you to consume Windows APIs directly from Objective-C. Currently, the bridge enables a very significant portion of the API surface and we aspire to reach the entire surface.
As an example, let’s examine how you could asynchronously invoke a browser in your app. Using the bridge, you can do this in one of two ways:
Option 1 (invoking the browser from c++/cx code):
[code lang=”cpp”]
auto uri = ref new Windows::Foundation::Uri("http://www.example.com");
concurrency::task<bool> launchUriOperation(Windows::System::Launcher::LaunchUriAsync(uri));
launchUriOperation.then([](bool success)
{
if (success)
{
// URI launched
}
else
{
// URI launch failed
}
});
[/code]
Option 2 (invoking the same API from your Objective-C code):
[code lang=”objc”]
[WSLauncher launchUriAsync:[WFUri createUri:@“http://www.example.com/”] success:nil failure:nil];
[/code]
(Objective-C blocks may be provided to handle the async success and failure cases).
In this example, not only are we consuming classes from Windows::System (“Launcher”) and Windows::Foundation (“Uri”), but we’re passing in an NSString and the projection system is “magically” treating this as an HSTRING to the underlying runtime. But it goes further: IVectors and IVectorViews may be treated as NSMutableArrays and NSArrays respectively, with similar mappings for iterators, enumerators, maps and morecoming soon. And, to make things easier, the lifetimes of objects — be they UWP or Objective-C — are managed through the same automatic reference counting semantics to which you’re already accustomed.
There’s a lot going on here and I reiterate that this is still being built out. In the meantime, take a look at some of our samples on GitHub to see this in more detail and in action.
XAML and UIKit: Together at Last
Now that you can call the Windows APIs from Objective-C, we didn’t want to limit your use of that API set. At all. To that end, rather than implementing a separate compositor for iOS/UIKit elements, the entire application uses the XAML compositor, with CALayers (which underlie essentially every View in iOS) being tied to corresponding XAML elements.
So let’s imagine that your app would like to (for example) play some video but, alas, the iOS bridge doesn’t support MPMoviePlayerController today. Through this mechanism you can create a XAML MediaElement, wrap it in a CALayer, wrap that layer into a view, and place that view with all your other UIViews. It’s that easy, and all your animations and transforms will work for this element as for any other.
[code lang=”objc”]
// WXCMediaElement is the Objective-C projection of
// Windows::UI::Xaml::MediaElement
WXCMediaElement *mediaElement = [WXCMediaElement create];
mediaElement.autoPlay = YES;
CALayer *mediaElementLayer = [CALayer layer];
[mediaElementLayer setFrame:CGRectMake(10, 10, 320, 240)];
[mediaElementLayer setContentsElement: mediaElement];
mediaElement.source = [WFUri createUri: @"ms-appx:///myvideo.mp4"];
// Now we just add the layer to be part of a UIView
[[containingView layer] addSublayer: mediaElementLayer];
[/code]
Our longer-term goal is to have coverage of most common classes in the SDK, and we welcome contributions from the community. In the meantime, we make it simple for developers to use XAML controls where the UIKit equivalent is not supported yet or where the XAML control would just look more “at home” in a Windows environment.
Looking ahead
The source for the bridge is now live at http://www.github.com/Microsoft/WinObjC/. This is the beginning of a journey. We are committed to working with the community to evolve the iOS bridge, and help iOS developers enable their code on the Universal Windows Platform. Today, we are sharing a preview of the SDK that’s used to build Windows 10 and Windows 8.1 apps built for x86 and x64 processor architectures. Later in the summer, we will add compiler optimizations and support for ARM (and therefore mobile).
We welcome all feedback, suggestions, questions, commentss. If you’d like to contribute to the project, we invite you to submit your code to the SDK on GitHub. You can also reach our dev team in a variety of ways:
- Tweet @WindowsDev and mark your questions with #winobjc
- Post questions to Stack Overflow and tag them with winobjc
- Visit the #winobjc channel on IRC (webchat.freenode.net)
We’re looking forward to your participation as we build out the SDK and, most of all, we’re excited to see all the great apps that you’ll build.