Using Cordova CLI on Mac OS X to build Android apps

This article [updated 7/2019] gets you up to speed on how to integrate your HTML/CSS/JS app with PhoneGap/Cordova into an Android app using a Mac (however, most of these steps work for iOS too) and prepare it for App Store submission. This article assumes you’ve already followed the steps here to set up your environment: Note: I no longer use Eclipse in my workflow.

I am referencing “cordova” in the command-line interface, not “phonegap.” This project will not use the PhoneGap Build service.

If you are making an app larger than 100MB for Google Play, you’ll need to make an expansion file. This 2014 article tells how to make one, though I don’t know if it works today. Amazon App Store allows apps up to 150MB before needing an expansion file.

Cordova uses the command-line interface (CLI) to generate the files needed to start the project. This article covers the creation of an app from CLI creation to upload a final apk to Google Play.

Create Cordova Project Files with CLI

1. Open a Finder window and select the folder you want to create your project’s folder inside of, such as /PhonegapApps
2. Open the Terminal app (click on its icon in the dock below, or click on the magnifying glass at top right and type in “terminal”), type cd and a space (for “change directory”), drag the selected folder to the Terminal screen, let go, click on the Terminal to select it, then hit Return. This will orient all commands to that folder.

For this project, all of your commands will always begin with “cordova.” Some online tutorials and PhoneGap documentation will tell you to use “phonegap;” in that case, change it to “cordova” and it should work fine.

3. Type the following in the terminal:

cordova create myApp

Basic files are generated in the /myApp folder.

4. Enter the new folder you created in Terminal with the cd (change directory) command:

cd myApp

5. CLI only downloaded the skeleton files needed for all platforms. Now you need to download the specific files for Android:

cordova platform add android

Open the myApp/platforms folder to see a new folder, /android.

Cordova included several files for a default one-screen app, complete with splashscreen and icon. To create a test apk file of the default Cordova app, type:

cordova build android

The apk file was built and saved as: myApp/platforms/android/app/build/outputs/apk/debug/app-debug.apk

(In the /outputs folder, you might double-click on the lint-results-release-fatal.html file to examine it.)

To run the apk on your device, you’ll need to go into your device’s Settings and enable for debugging. I have Google Drive installed on my Android device and computer. It’s a simple matter to copy the file to Google Drive on the computer, turn on my device, open Google Drive there, and select the apk file to download, install and run it. You’ll know it’s running correctly when you see “APACHE CORDOVA DEVICE IS READY” on the screen.

For subsequent versions of the app, I always run the Refresh command in Google Drive to make sure I’m referencing the latest version of the app.

If you only have one platform installed, you can shorten the command above to “cordova build” and “cordova emulate.” If you have more than one platform installed, “cordova build” will build each platform.

If you have an early cordova version installed (check with “cordova -v”), you can update to the latest version with:

npm update -g cordova

I once received the message after inputting the above:

npm ERR! Error: EACCES: permission denied

You need to reclaim ownership of the .npm directory by typing this in the console, where xxx is the name at Macintosh HD/Users/xxx/:

sudo chown -R xxx ~/.npm

… and need the write permission in node_modules directory by typing this in the console:

sudo chown -R xxx /usr/local/lib/node_modules

About Cordova Serve

We can also view the app in the browser with:

cordova serve android

I get this returned in the Terminal:

Static file server running on port 8000 (i.e. http://localhost:8000)
CTRL + C to shut down

I opened a browser and copied/pasted the above URL in and saw a screen of text. Android was underlined, so I clicked on that and the app startup screen appeared. I clicked on OK to get rid of the message info box (which pops up when the default screen is not showing in a mobile device). The message displayed was, “APACHE CORDOVA Connecting to Device.” That is correct behavior for the default Cordova app — the message won’t update because the desktop monitor is not a “device” to connect to.

This is a “static” file, meaning if you opened the html page, made a change, and saved it, refreshing the browser will not show the changes.

I clicked on the Terminal and then CTRL + C returned me to the prompt.

Update config.xml


You’ll notice that the apk name was not “myApp.” To rectify that, open the myApp/config.xml page in a text editor. Change the <widget id= line to your reverse domain name or bundle identifier (Apple’s term), such as com.developerName.myApp. On the same line, put the correct version number, from 0.0.1 to 1.0.0, for instance.

Change <name>HelloCordova</name> to your app’s name: <name>myApp</name>.

Update the <description> and <author> information with your own.

Go ahead and replace the default Cordova resource files with your own. In other words, you can safely delete the /www/css, www/img, and /www/js folders. Replace the entire /www/ contents with your own HTML/CSS/JavaScript files and all other content files, like images and videos. (For this blog’s sake, I’m keeping the Cordova default app contents.)

In the <widget tag, add:




… with a space before and after.

Learn more about versioning at

The top of my config.xml page begins like:

<?xml version='1.0' encoding='utf-8'?>
<widget android-versioncode="1" id="com.[companyname].[appname]" version="1.0.0" versionName="1.0.0" xmlns="" xmlns:cdv="">

Replace [companyname] and [appname] with your own information.

To learn how else you can modify this file, please read

When I did a cordova build android, the old name was still there. So I removed the android platform with the following code (WARNING: the entire /platforms/android folder and all its contents will be removed with this command, so if you have added any content like splashscreen images, you’ll want to copy them to another folder first):

cordova platform rm android

… then added it again with:

cordova platform add android

… and the new name appeared when I did a cordova build.

Add a Cordova API plugin

To implement Cordova features into your app, you’ll need to add the following to the head of the index.html page, as well as any page that uses Cordova APIs (application programming interface) such as InAppBrowser or SplashScreen:

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: 'unsafe-eval'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; media-src *">
< script type="text/javascript" src="cordova.js"></script>
< script>
// Wait for device API libraries to load 
document.addEventListener("deviceready", onDeviceReady, false); 
// device APIs are available 
function onDeviceReady() { }

(WordPress no longer retains formatted script tags in a document that contains opening and closing angle brackets, but I was able to include them above by inserting a space after an opening bracket like this: < script. If you copy/paste the above, make sure you remove that space from two locations.)

The cordova.js file will be added for you at build time; no need to add it manually.

If you have questions about the <meta http-equiv=”Content-Security-Policy” lines, please read these pages:

Note the reference to cordova.js. This line must point to the www/ folder. If the page is in www/chapters/here.html, then you would add ../ for each folder away from www/; so in this case the line would read:

< script type="text/javascript" charset="utf-8" src="../cordova.js"></script>


1. [step skipped]

2. Open MyApp/config.xml and add:

<allow-intent href="http://*/*" launch-external="yes" />
<allow-intent href="https://*/*" launch-external="yes" />

If you are using telephone, external URL links, and other link formats, then you’ll want to add the following to make sure they work.

<access origin="tel:*" launch-external="yes"/>
<access origin="geo:*" launch-external="yes"/>
<access origin="mailto:*" launch-external="yes"/>
<access origin="sms:*" launch-external="yes"/>
<access origin="market:*" launch-external="yes"/>

Add the InAppBrowser Plugin


Cordova adds extra functionality via plugins. Each plugin has its own code and must be downloaded separately. As an example of this process, we’ll load the InAppBrowser (IAB) plugin to the app. InAppBrowser enables external links in our app to remain in the app, otherwise an external link will take the user out of the app and open a browser. Then the user would need to exit the browser and reopen the app. The IAB will instead open a webView window to display the page, and a Done button (in iOS at bottom left) or an X (in Android at upper right) will close the window and return one to the app. The core Cordova plugins are here:

1. To install the IAB, make sure the Terminal shows the starting point as myApp, then type:

cordova plugin add cordova-plugin-inappbrowser

You’ll see it installed in /myApp/plugins

To see all available installed plugins, type:

cordova plugin list

2. [Step dropped for Cordova CLI 5.0+.]

3. Now we follow the instructions to style our links so they open in the IAB. For instance:

<a href="#" onTouchEnd="'','_blank');"> IAB with location bar (showing URL)</a>

For email, do the normal:

<a href="">Email:</a>

4.  Open PhoneGap’s /myApp/www/index.html page and replace portions with the following lines in these inAppBrowser instructions:

(For information about the <meta http-equiv=”Content-Security-Policy” lines, please read this.)

I edited the default Cordova project’s index.html page with the above page, typed cordova build android to build the apk, moved myApp-debug.apk to Google Drive, and opened it in my device. The screen shows several buttons, each one showing a different way to implement IAB, and what happens if you don’t use it. IAB works. Mission accomplished. Now you need to add the deviceready code to the top of all pages where you have external links, and make sure the links conform to the IAB link format.

5. Once I got the debug app loaded on my device for testing, I tapped on a link and got the dreaded error popup: “Your app has stopped working.” The rest of the app worked and the external link did not. So I updated the InAppBrowser plugin, tested again, and it worked.

Update AndroidManifest.xml

  1. You can skip #1. I don’t see AndroidManifest.xml under /android or anywhere else any more.

You’ll want to update myApp/platforms/android/AndroidManifest.xml with your permissions. Almost all of these are missing; enter ONLY what’s required for your app (the top one should already be there — if it weren’t, then the IAB would not have retrieved the page). You don’t need to update this page for the sample Cordova app.

More information:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> 
<uses-permission android:name="android.permission.READ_CONTACTS"/> 
<uses-permission android:name="android.permission.WRITE_CONTACTS"/> 
<uses-permission android:name="android.permission.GET_ACCOUNTS"/> 
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

2. Update the version code as well if it’s more than version 1. VersionCode is what will display in the store; versionName is for your internal use and won’t be shown: android:versionCode=”10000″ android:versionName=”1.0.0″ [Note on format: “10000” = 1.00.00. Earlier versions of ADT accepted “android:versionCode=”1” but no longer.]

3. Make sure the following is accurate (it may still have cordova’s information instead):


4. Make sure the targetSdkVersion number is the latest API – read this to check: :

android:targetSdkVersion=”27″ />

(Note that you might need to install the Android Studio SDK that matches the above number.
1. Start Android Studio.
2. Configure > SDK Manager.
3. Select the SDKs needed and Apply.
4. Accept conditions and go.)

5. Make sure the minSdkVersion is reasonable. Again, read the link above.

<uses-sdk android:minSdkVersion="26"

Add Your Icons


This free service works fine for generating all your icons from a single artwork: You simply drag a 512×512 png icon to the screen and it immediately makes icons. Then click on the Android button to see the icons grouped individually for each platform. Just right-click each icon and save to its proper place as icon.png (in Android, to the myApp/res/drawable folders). You might want to create a 36×36 icon for the ldpi folder, although Google does not seem to require it.

You may have noticed that the Cordova icon appears on your home screen on your test device. Let’s replace it with your own. First make your 512×512 icon design, then use the service above (or not) to make the multiple size versions.

1. Open /platforms/android and copy the /res folder to your root folder, making /myApp/res.

2. In config.xml just above the </widget> line, put:

<platform name="android"> 
 <icon src="res/drawable-ldpi/icon.png" density="ldpi" />
<icon src="res/drawable-mdpi/icon.png" density="mdpi" />
<icon src="res/drawable-hdpi/icon.png" density="hdpi" />
 <icon src="res/drawable-xhdpi/icon.png" density="xhdpi" />
 <icon src="res/drawable-xxhdpi/icon.png" density="xxhdpi" />
 <icon src="res/drawable-xxxhdpi/icon.png" density="xxxhdpi" />

Note that Cordova does not provide all the folders that Android requests. So create the /xxxhdpi folder as shown and fill them with the following sizes of icons.


/drawable-xxxdpi = icon.png, 192 x 192px (4x mdpi). No splash.

3. Replace all the above stock Cordova icons in /myApp/res/drawables with your own. (This page gives all the icon sizes:

4. In addition, delete all the folders in both /res locations that don’t apply to your app — that you aren’t providing icons for. I’m talking about the “land” and “port” folders. Leave the ic_action*.png images in the /platform/android/res/drawable* folders — they are for the InAppBrowser plugin icons.

The above config.xml icon.png entries is using only four folders. If you are going to use more than four folders, then they should be listed in the config.xml file in the same format.

The reason I copy the /res folder to the root /myApp folder is to preserve the icons in case I need to remove the android platform and add it again. Removing the android platform means that the entire /platforms/android folder will be deleted, and all those icons and screens will be lost.

6. Go ahead and test in your device with cordova build android. After you exit the app, look for the app icon among the others and make sure the correct icon is showing. If a Cordova brand icon is shown, then delete all the icon.png files in the /myApp/platforms/android/res/drawable folders and test again. If it still doesn’t work, then just copy the /drawable folders over to the /platforms/android/res folder.

How do we install the app in the device? I install it in my device by installing Google Drive on my desktop and its corresponding app from Google Play in my device. I drag the CordovaApp-debug.apk file in Finder to the Google Drive window and wait until it finishes uploading. In my device, I open Google Drive and tap on the file. It downloads and asks if I want to install it. I accept, and tap again later to open and test.

Tip From time to time I get error messages in the console (don’t we all?). What I do is post the error information from the console into a dedicated text file along with my attempts that failed and the solution. The file is saved to the desktop where it is always at hand, and in Google drive where I can access it among my other computers. When I come upon an error, I can do a search for the error in that file to see if I’ve had the problem (and solution!) before.

Recently, after doing cordova build android while following the steps on this page, I had the console error:

Error: ENOENT: no such file or directory, scandir '/Users/.../platforms/android/src/com/...'

Based on my online web searches, these approaches did not work:
.  npm cache clean
.  cordova prepare android
.  Created subfolders: /src/com/… [“Error: No Java files found which extend CordovaActivity.”]

These steps worked:

cordova platform rm android
cordova platform add android
cordova build android

Add Your Splash Screen

We add splashscreen functionality with a plugin. In Terminal, making sure it starts within your myApp folder, add the plugin with:

cordova plugin add cordova-plugin-splashscreen

(To remove a plugin in the future, type cordova plugin list and view the list of available plugins, then type cordova plugin rm and copy/paste the plugin line, like cordova-plugin-splashscreen, then hit Enter.) You’ll find a list of plugins already installed in /myApp/plugins.

You can create the same size splash screens as the default Cordova screens and replace them, or make them as 9-patch images. Both ways are covered below.

I. Replace Cordova images

Copy the /platforms/android/res/drawable* folders into your /myApp/res folder. Delete the /values and /xml folders from myApp/res only.

Default Cordova Android splash screen sizes:
land-hdpi: 800×480
land-ldpi: 320×200
land-mdpi: 480×320
land-xdpi: 1280×720
port-hdpi: 480×800
port-ldpi: 200×320
port-mdpi: 320×480
port-xdpi: 720×1280

Here’s how I quickly made the above sizes to replace them. Make a 700x700px icon in Photoshop (can make vector artwork first, then paste it into Photoshop at 700x700px). Easily make the sizes with these steps, saving each as screen.png in their respective folders in /myApp/res:
1. Use Image > Canvas Size to enlarge to the 720×1280 and 1280×720 sizes, landscape and portrait.
2. Use Image > Canvas Size to bring back to 700x700px.
3. Image > Image Size to reduce to 300px.
4. Image > Canvas Size to create the next four sizes, 800×480, 480×800, 480×320, 320×480.
5. Image > Image Size to bring to 200x200px.
6. Image > Canvas Size to make the final sizes, 320×200, 200×320.

Copy the folders from /myApp/res to /platforms/android/res/. This replaces the default Cordova screens. Since you are copying these directly into /platforms/android/res/, you don’t need to enter anything into the config.xml file.

Continue with “Final Steps” below.

II. Make 9-patch Images

Create your splash screens as 9-patch png images. For instructions on how to do this, see my article here:

The size for each should be:
xxlarge (xxhdpi): 1152 x 1536px.
xlarge (xhdpi): at least 720 x 960 (Cordova used 720 x 1280)
large (hdpi): at least 480 x 640 (Cordova used 480 x 800)
medium (mdpi): at least 320 x 470 (Cordova used 320 x 480)
small (ldpi): at least 200 x 320 (Cordova used 200 x 320)

There is no splash screen for the xxxhdpi folder.

In the Icons section above, I had you copy/paste the /platforms/android/res folder to the root /myApp folder, which created a /myApp/res folder. Add all your splash images to the /myApp/res/drawables folders. Delete their splash images and add your own and name each one as splash.9.png.

Final Steps

If you remove and add the Android platform (with cordova platform rm android and cordova platform add android), you can simply copy the folders within /myApp/res and paste them into the other /res folder, overwriting the same-named /drawable* folders while preserving the non-drawable folders that are needed (/values and /xml). Icon files are copied over automatically at build time; splash screen images are not! So you’ll need to copy the /drawable* folders over any time you change your splash images.

In /www/config.xml, include above the </widget> line put the following. This assumes you made your splash screens of the filename “splash.png.” if you made it “screen.png” then update the “splash” to “screen:”

<preference name="SplashScreen" value="splash" /><!-- prefix of splashscreen's splash.png name -->
<preference name="SplashScreenDelay" value="2000" /><!-- view for 2 seconds-->

(Note that with “org.apache.cordova.SplashScreen,” you should pay attention to case — it’s not all lowercase.)

In your index.html, add the navigator.splashscreen.hide(); line here:

document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {

Highlight and copy your myApp/res/drawable folders and paste them into /myApp/platforms/android/res/. You should check that you are replacing them when the alert pops up asking if you want to replace.

Go ahead and test in your device with cordova build android. Make sure the splash screen shows before your app does. Make sure your icons are correct.

What if you need to use different versions of pages for different platforms?

a) I needed the home page of my app to be different on Android and iOS. That’s what the myApp/merges folder is for. The myApp/merges/android folder is the same as your myApp/www folder, so I moved the index.html file to the merges/android folder. When I did a cordova platform add ios, it created a merges/ios folder. I copied the index.html file there and made the changes for the iOS version. So when I do a cordova build ios or android it will use the correct file for each build.

b) When styling links for YouTube in the InAppBrowser, onclick=”” works in iOS to open a YouTube link in IAB but not in Android (it didn’t work in my Nexus 7). So I put differnt versions of those pages in /merges/android and /merges/ios, each page with its own link style:


< a href="#" onclick="'', '_blank');">


< a href="">

The Android link did not appear in IAB, but that was fine – the user simply used the Back button to return to the app.

c) If you have a /www/css folder and want different style sheets for each app, just create a /css folder inside each merges platform folder (like myApp/merges/android/css/style.css) and put the css there instead of in the /myApp/www/css folder. That will style each platform differently according to your CSS files.

To quickly test this, create a /merges/android folder if you don’t have one and simply move the /www/index.html file there. Open the index.html file and add the following right after the button code we added earlier:

This index.html page is in the /platforms/merges folder.

Go ahead and test in your device with cordova build android. The above text should appear at the bottom of the screen.

About the myApp/Hooks Folder

If you open myApp/hooks, you’ll see a readme text file there. That folder is for adding scripts that will execute as part of your CLI operation. For instance, you can add a before_build script which will automatically add all your plugins before the actual build commences. So each time you create a new app, you’ll copy/paste that file into the new app’s /hooks/before_build folder. I’m not familiar enough with this process to explain it here, but if you already know node.js scripting, you might look into it. For instance, this page gives the hooks steps for automatically creating app icons (requires installation of Homebrew and ImageMagick):

Update Cordova

1. If you encounter issues with an individual plugin, by all means let your debugging include removing the plugin and adding it again. To do that, follow these steps:

a. In terminal: cordova plugin ls to see the plugins installed. Highlight the plugin you want to remove, and copy it.

b. In terminal: cordova plugin rm and paste in the copied plugin (like this: cordova plugin rm cordova-plugin-inappbrowser). Hit Enter.

c. To install again, in terminal: cordova plugin add and paste in the copied plugin (like this: cordova plugin add cordova-plugin-inappbrowser –save). Hit Enter.

Note that Cordova does not have a way to update plugins. If you know of an updated plugin, then you simply following the a, b, c steps above to install the new plugin version.

2. If you need to update Cordova, then do this way:

npm update -g cordova

3. To update a particular platform (perform this command one at a time for each platform):

cordova platform update android

Delete DS_Store files

You won’t want to clutter your app with .DS_Store files. Open Terminal, start it at your app’s root folder, then type and run:

rm -f .DS_Store

Build your apk file for upload to an app store

You’ll need to create a release version of the app to upload to an app store. Up to now, you’ve been building a debug version of the app. To build a release version of the app with Cordova’s CLI method in the terminal, follow these steps:

Prepare Copy and Other Graphic Assets for App Store

You’ll need this information on hand when filling out the form for apk submission within Google Play. Follow these steps:

Ready For Public Release

Congratulations! You are now ready to show off your baby to the world!

To register as a Google Play developer and set up your publisher account, visit the Google Play publisher site:

My Helpful Links page gives a small listing of other sites where you can upload your apps. Visit and look under “App Stores.”

Further Recommended Steps

If you are going to be involved with Apache Cordova regularly, keep up to date with the release announcements of upcoming versions, updated plugins, and other news.

Helpful links:

Official site:

Cordova news:

Online support:

Join Google Groups for help and contribution:!forum/phonegap


5 thoughts on “Using Cordova CLI on Mac OS X to build Android apps

  1. Pingback: Using Android Studio Beta with Cordova PhoneGap | iPhone Dev Log

  2. Pingback: Using PhoneGap 3.0 CLI on Mac OS X to Build iOS and Android Projects | iPhone Dev Log

  3. Pingback: Submitting an Android App to Amazon | iPhone Dev Log

  4. I used this procedure with my own Android Cordova app. I followed the example using my own source. Everything went perfectly except my mp3 files would not play and no error was displayed, code was clean. The same program using the iOS instruction ran perfectly. Would you know why audio can be an issue. I am using HTML5 (audio tag), jQuery mobile and CSS.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.