Tutorial: Embed PhoneGap as a Subview in your Native iOS Application
Something cool that many mobile developers (and particularly native developers) might not be aware of at this point, is the option to use PhoneGap (aka Cordova) as a component within your mobile application, as a web “subview” of a whole native application where you want to render HTML/JS content and/or interact with the PhoneGap APIs. In this webview component (sometimes also referred to as Cleaver), you can do anything a traditional PhoneGap application would do, such as access native features like the camera or contacts etc too. This post will expand the steps here and show you a sample application you could download and try yourself. Note that I am not an Objective-C native programmer, but this is just a simple example to show off the capabilities and create awareness. Feel free to post your application or source if you have used this and would like to share with others
.
Steps to Embed Cordova WebView
Below are detailed steps on including PhoneGap/Cordova as a web subview in your native application. At the end of this section I show screenshots from a sample application I made available on my github account for you to try this out yourself or refer to things as needed.
- Create your base native iOS application in XCode (version 4.5 recommended) unless you just plan to add to an existing native application.
- Download and extract the Cordova source to a permanent folder location on your hard drive (for example: ~/Documents/Cordova).
- Close any other Cordova projects and exit XCode (XCode can be quirky, a restart often clears up potential or possible errors).
- Navigate to the directory where you put the downloaded Cordova source above and copy the Cordova.plist file into your native application folder on the file system (at same level as the AppDelegate files etc, see picture below). Note: you could also use a Cordova.plist from a newly created Cordova application.
[box type="info"]
This file contains specific Cordova property settings and plugins required for your application to use Cordova.
[/box] - Drag and drop the Cordova.plist file into the Project Navigator of Xcode
- Choose the radio-button “Create groups for any added folders”, select the Finish button
- Go to the downloaded source from the previous step above and locate the CordovaLib.xcodeproj in the CordovaLib sub-folder. Drag and drop the CordovaLib.xcodeproj file into the Project Navigator of XCode (at the same level as the .plist file copied in above – again choosing ‘Create groups for any added folders‘)
- Select CordovaLib.xcodeproj in the Project Navigator
- Open the File Inspector with Option-Command-1 or by going to View | Utilities | Show File Inspector
- Ensure that it says “Relative to Group” in the File Inspector for the Location drop-down menu similar to below:
- Select the project icon in the Project Navigator, select your application under “TARGETS” (should have an A next to it), then select the “Build Settings” tab as shown below:
- Locate the setting for “Other Linker Flags” (under the Linking section) and double-click the value text field to bring up the box to enter the flags
-all_loadand-Obj-Cas shown here: - Select the project icon in the Project Navigator, select your target, then select the “Build Phases” tab.
- Expand “Link Binaries with Libraries”. Select the “+” button, and add these frameworks (and optionally in the Project Navigator, move them under the Frameworks group):
AddressBook.framework
AddressBookUI.framework
AudioToolbox.framework
AVFoundation.framework
CoreLocation.framework
MediaPlayer.framework
QuartzCore.framework
SystemConfiguration.framework
MobileCoreServices.framework
CoreMedia.framework - Now expand “Target Dependencies”
Select the “+” button, and add the CordovaLib build product - Expand “Link Binaries with Libraries” again and add libCordova.a
- Go to “Xcode Preferences -> Locations -> Derived Data -> Advanced…” and ensure it is set to “Unique”
-
Go back to Build Settings and locate the Header Search Paths and ensure the following properties are set (including the quotes):
“$(TARGET_BUILD_DIR)/usr/local/lib/include”
“$(OBJROOT)/UninstalledProducts/include”
“$(BUILT_PRODUCTS_DIR)”
In my case I chose to create a new Single View Application in XCode such as the following:
[box type="info"]
You’ll need this for copying Cordova resources into your native application.
[/box]
Code Additions
To actually use the subview, you need to add the following Objective-C code where you want to include it.
Import the following header
#import <Cordova/CDVViewController.h>
Instantiate a new CDVViewController
CDVViewController* viewController = [CDVViewController new];
Set up the view frame
viewController.view.frame = CGRectMake(0, 0, 320, 480);
Lastly, add to your view as a subview
[myView addSubview:viewController.view];
You could optionally set the www folder, start page or option to show the splash screen to something other than the default (default folder is www, start page is index.html and splash screen is no) on that CDVViewController as well with the following lines:
viewController.wwwFolderName = @"myfolder"; viewController.startPage = @"mystartpage.html"; viewController.useSplashScreen = YES;
Here’s an example of actually implementing those lines above in my ViewController.m class that is created with a new native XCode Single View project like discussed above (the added code is in the viewDidLoad function):
#import "ViewController.h"
#import <Cordova/CDVViewController.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
CDVViewController* viewController = [CDVViewController new];
viewController.view.frame = CGRectMake(0, 40, 320, 450);
[self.view addSubview:viewController.view];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
- (void)dealloc {
[super dealloc];
}
@end
[box type="info"]
Since we added the above code to create a new CDVViewController into our main ViewController, we could reuse this class anywhere in our application and it will automatically include the Cordova subview. In the storyboard file in XCode (the UI environment), you can actually set the class of any given View Controller object to ViewController and you will get a new Cordova WebView subview component automatically due to this code. You can simply set the class to it if it’s not selected already in the Identity Inspector as shown here:
In my sample application you can see it when you press the Open a new Cordova WebView button. You could choose to add this code wherever you need it, this is just one example for simple illustration.
Sample Application
In the first screenshot below, the header navigator and tab bar at the bottom (with badge), and the second view with all the text and controls are actually native iOS controls, whereas the middle embedded view with the button list is an embedded Cordova WebView containing HTML/JS to interact with the native Cordova/PhoneGap APIs to retrieve contacts, use the camera, etc.
If you’re familiar with Storyboarding in XCode for iOS, the Storyboard shows an overview and flow of the application from the native perspective, so you can see the parts which are iOS Native controls versus the other buttons etc that were included from the HTML/JS as part of the Cordova WebView:
In the next screenshot you can see how we can interact with the Cordova/PhoneGap APIs for native functions like grabbing contacts right there inside our native application:

This next view is all native iOS controls (see storyboard), but includes a button to pop up a new view that uses the same ViewController class and will have the embbeded Cordova subview:
And lastly is our next view from the button pop-up that shows how another view will also have the embedded Cordova WebView:

Grab the sample application from my github account and give it a whirl.
There’s an advanced tutorial dedicated to embedding PhoneGap for Android here, so be sure to check that out too!
Filed in: Cordova • HTML/JS • iOS • Mobile Development • PhoneGap















Thanks Holly!
I was just looking for this solution and phonegap posted it on their facebook page.
Saved me many an hour of googling.
Hello,
thanks for sharing this. It’s great this is possible. I was wondering if same thing can be achived on Android.
Thanks,
ukw.
Hi there, yes it can, there’s a video here on embedding CordovaWebView with Android with links to a sample project…
Thanks!
Holly
Thanks!
Holly,
We are having some issues getting push messaging to work inside adobe flex mobile. Would it be possible to embeed these phone gap functions inside a flex mobile application.
I am considering converting my app which is written in 100% JavaScript / CSS / HTML5 into more of a hybrid app using this approach. I am wondering if adding a storyboard and swapping views that way (native) would be better performance-wise than swapping views in pure JavaScript (current approach). My main concern would be the amount of time it takes for a Cordova WebView to initialize.
I would be curious to hear your thoughts on this. And thanks for the write-up!
Hi Matthew! I’m not sure I could say 100% myself without trying it. I do think it’s a great question and could make for an interesting approach. I’m going to run this by some of our PG guys to get some feedback and will get back to you ~ Thanks! Holly
Thanks Holly, I’m looking forward to hearing what they have to say!
Hi Holly
I can’t get this to work. I get the following error when I try to run the app in the simulator.
Undefined symbols for architecture i386:
“_OBJC_CLASS_$_CDVViewController”, referenced from:
objc-class-ref in SecondViewController.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Any idea what I’ve done wrong?
Thanks
Tracey
Hi Tracey, what version of XCode and PhoneGap are you using?
Hi Holly
I’m using Xcode Version 4.5 (4G182) and Cordova 2.1.1.
Thanks
Tracey
Tracey – try this:
http://stackoverflow.com/a/12731951/170237
I also changed the scheme to ‘CordovaLib’ built the project and then switched back to my project scheme.
this helped me out of the same problem. pls have a try.
http://stackoverflow.com/questions/15261774/xcode-linker-error-when-upgrading-to-phonegap-2-5-0
Hi Holly,
Thanks a lot for this amazing tutorial, It works ok but I believe that the source code in the github is not complete.
Hi there, could you expand on what you mean? Thanks! Holly
I see the same thing. GIT project has no code outside of what Xcode generates for a template project.
Hi Holly,
I believe she means that the sample project in github contains none of the functionality of this tutorial – it is simply an empty project. It would be super helpful if you included your fully realized test project so that one can see how the different bits and pieces fit together.
Cheers,
C.
Sorry all, the project sample in github was supposed to have the full working sample. I will investigate and repost as soon as I have a chance in the next couple days. Cheers, Holly
Hi guys, I updated the sample project so you should be able to get the latest project now from the same location on github here… Please let me know if you have issues getting the latest. The Cordova webview is added via the CDVViewController addition in the ViewController.m file here.
Hope this helps, sorry about that!
Holly
Hi Holly,
I’m having trouble making this work, I followed the instructions and I’m able to run the app and get the index.html to showup in Cordova webview, but the “deviceready” is not being fired. No erros reported in console.
I was able to use the command-line tools to build the cordovalib and simulate the app and get deviceready to fire, but when I create my own app, and then add cordovalib project and setup a CDVViewController, it opens index.html and does not fire deviceready, can u help me debug
I am having this same issue… and have been trying to solve the problem since yesterday. It seems that the CDVViewConroller.m class is being initialized incorrectly or it is referenced incorrectly.
The CDVViewConroller.m class never dispatches the “deviceready” event because its “dealloc” method is dispatched almost immediately after loading. Its “webViewDidStartLoad” and “webViewDidFinishLoad” methods are also never called.
I’m new to iOS/phone gap so it could be that the solution is simple, but so far I am stumped.
Hi, Rakshith
I also have that problem, it open the index.html, but it does not fire the deviceready event whatever.
@Holly, I use XCode 4.6 and Phonegap 2.5.0, I am new to phonegap, I super hope if you could have any help for this? Thanks any way!
Thanks Holly,
Have you heard about migMobile?
migMobile – is a cross-platform framework that allows you to build fast and fluid native mobile applications in the language of your choice. We provide a common standardized API across the different platforms/operating systems. The application developed on one can be quickly and easily transferred to the others. In real world applications we have realized on average a 70% reduction in development time required to transfer to subsequent platforms.
You can find more details at the following link:
http://www.kickstarter.com/projects/1008546182/migmobile
Hi Holly,
I’m trying your tutorial. I am new on native iOS programming, but I have some experience about Phonegap and Cordova Apps. I am mired on Code Additions Section cause I don’t have idea where I have to add this code lines.
My idea, is make an app with diferents tabs, where sometimes i would use native, and anothers, i would use phonegap and HTML5 code.
Hi Marc, It really just depends where in your application you want to use the webview. The code additions piece is added to the native code depending on where you want to include a subview that’s HTML. Do you have some code already you could share so I could help point out better where you might want to add it? Thanks! Holly
Hi Holly and thanks for your fast answer.
I upload a screenshot: http://www.ideai.net/clients/screenshot.png
Can I download your complete and final super-app xCode project?
Thanks a lot!
Hi Holly,
You sample project on GIT is empty i.e. there is no code in there besides what is auto generated by Xcode for a template project.
Rob
Hi Holly, thanks for this tutorial. I’d love to download the completed app, but it looks like the GitHub project doesn’t have everything pushed to it.
For example, the ViewController doesn’t include any Cordova classes: https://github.com/hollyschinsky/NativeAppEmbedWebView/blob/master/NativeAppEmbedWebView/ViewController.m
Would you be able to push the completed project, including the tab bar? I’m working on a similar problem, and having working code would be really helpful. Thanks!
Hi Holly,
Thanks a lot for this amazing tutorial, I had been searching for this example for the past 3 days. I need to embed PhoneGap as a subview in my native single view IOS Application. I have one issue regarding this concept. I need to use Web services url by giving login credentials(View) and get json response (a URL) and need to access that response(url) by using phone gap framework. Do you have any idea regarding this issue (or) any tutorial with you. Thanks in advance…..
Hi, I managed to load Cordova 2.5.0 into my embedded ios app running on SDK 6.1. However, during run time on my device, cordova lib is not fully loaded – I cannot get the function document.addEventListener(“deviceready”, deviceInfo, false); to work.
But yet surprising, even though I cannot call the get_contact function, i still can get get_location function to work.
I got a run time error: CDVPlugin class CDVSplashScreen (pluginName: splashscreen) does not exist.
I suspect this is causing the cordova lib not to be fully loaded.
Any idea how to solve it. Many thanks!
hey Kevin
go to “config.xml” file
delete plugin name “SplashScreen” then try to run your project
The most recent versions of PhoneGap use “config.xml” instead of “Cordova.plist”. Would you follow the same instructions using the XML file?
How to create multiple webviews in Cordova/phonegap architecture ? any pros/ cons using this ? I have done profiling through instrument , didn’t find any leakage, still my app crashes after 30 mins. How to deal with this ?
HI Holly:
I’m new to integrating the native app with PhoneGap one. When I was running the GIT project you posted , I got an error finding file. Am I missing something? Thanks in advance
the missing file was “Cordova/CDVViewController.h” . Where can I located? thx