A Grunt plugin to provide build tasks for Phonegap applications
grunt-phonegap
integrates Phonegap development with Grunt-based workflows
by wrapping the Phonegap 3.0 command line interface.
Rather than polluting the top-level of your project, grunt-phonegap
copies your files into a
subdirectory containing the Phonegap project, which gets regenerated every time the task phonegap:build
is executed.
- Requirements
- Getting Started
- Overview
- Dynamic config.xml
- App Icons
- versionCode
- Android Debugging
- minSdkVersion and targetSdkVersion
- Android Permissions
- Android Screen Orientation
- Application Name
- Phonegap Build
- Tasks
- Running the test suite
- Contributing
- Release History
- License
You will need the phonegap
CLI tool installed globally to use grunt-phonegap
.
npm install phonegap -g
You should also install whatever system dependencies are required by the platforms you intend to target.
For help with that, see Platform Guides from the Phonegap documentation.
If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
The easiest way to start a new project is with the grunt-init-phonegap template.
It will ask you some basic questions and then generate a project skeleton in your current directory.
git clone https://github.com/logankoester/grunt-init-phonegap.git ~/.grunt-init/phonegap
mkdir myapp
cd myapp
grunt-init phonegap
Once the skeleton has generated, open up your new Gruntfile.coffee
add one or more platforms to the list.
Your app is ready to build! [Skip to Tasks] to see how.
npm install grunt-phonegap --save-dev
Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
grunt.loadNpmTasks('grunt-phonegap');
In your project's Gruntfile, add a section named phonegap
to the data object passed into grunt.initConfig()
.
Point phonegap.config.root
to the output of your other build steps (where your index.html
file is located).
Point phonegap.config.config
to your config.xml file.
phonegap.config.cordova
should be the .cordova
directory that is generated by phonegap create
. It must
contain a config.json
file or your app cannot be built.
grunt.initConfig({
phonegap: {
config: {
root: 'www',
merges: 'merges', //(Optional) You may specify folder with your platform specific assets
config: 'www/config.xml',
cordova: '.cordova',
cli: 'cordova', // (Optional) Default to `phonegap local`
html : 'index.html', // (Optional) You may change this to any other.html
path: 'phonegap',
cleanBeforeBuild: true // when false the build path doesn't get regenerated
plugins: [
'/local/path/to/plugin',
'http://example.com/path/to/plugin.git',
{
id: 'git://example.com/example/repository',
variables: [
{
name: 'APP_ID',
value: 'EXAMPLE_ID'
},
{
name: 'CLIENT_KEY',
value: 'EXAMPLE_KEY'
}
]
}
],
platforms: ['android'],
maxBuffer: 200, // You may need to raise this for iOS.
verbose: false,
releases: 'releases',
releaseName: function(){
var pkg = grunt.file.readJSON('package.json');
return(pkg.name + '-' + pkg.version);
},
debuggable: false,
// custom properties overriding AndroidManifest.xml
androidManifest: {
// properties added to <application>
application : {
},
// properties added to <activity>
activity : {
"android:launchMode":"singleTask" // This is necessary to force single app instance.
}
},
// Must be set for ios to work.
// Should return the app name.
name: function(){
var pkg = grunt.file.readJSON('package.json');
return pkg.name;
},
// Add a key if you plan to use the `release:android` task
// See http://developer.android.com/tools/publishing/app-signing.html
key: {
store: 'release.keystore',
alias: 'release',
aliasPassword: function(){
// Prompt, read an environment variable, or just embed as a string literal
return('');
},
storePassword: function(){
// Prompt, read an environment variable, or just embed as a string literal
return('');
}
},
// Set an app icon at various sizes (optional)
icons: {
android: {
ldpi: 'icon-36-ldpi.png',
mdpi: 'icon-48-mdpi.png',
hdpi: 'icon-72-hdpi.png',
xhdpi: 'icon-96-xhdpi.png'
},
wp8: {
app: 'icon-62-tile.png',
tile: 'icon-173-tile.png'
},
ios: {
icon29: 'icon29.png',
icon29x2: 'icon29x2.png',
icon40: 'icon40.png',
icon40x2: 'icon40x2.png',
icon50: 'icon50.png',
icon50x2: 'icon50x2.png',
icon57: 'icon57.png',
icon57x2: 'icon57x2.png',
icon60: 'icon60.png',
icon60x2: 'icon60x2.png',
icon60x3: 'icon60x2.png',
icon72: 'icon72.png',
icon72x2: 'icon72x2.png',
icon76: 'icon76.png',
icon76x2: 'icon76x2.png'
}
},
// Set a splash screen at various sizes (optional)
// Only works for Android and IOS
screens: {
android: {
ldpi: 'screen-ldpi-portrait.png',
// landscape version
ldpiLand: 'screen-ldpi-landscape.png',
mdpi: 'screen-mdpi-portrait.png',
// landscape version
mdpiLand: 'screen-mdpi-landscape.png',
hdpi: 'screen-hdpi-portrait.png',
// landscape version
hdpiLand: 'screen-hdpi-landscape.png',
xhdpi: 'screen-xhdpi-portrait.png',
// landscape version
xhdpiLand: 'www/screen-xhdpi-landscape.png'
},
wp8: 'SplashScreenImage.jpg',
ios: {
// ipad landscape
ipadLand: 'screen-ipad-landscape.png',
ipadLandx2: 'screen-ipad-landscape-2x.png',
// ipad portrait
ipadPortrait: 'screen-ipad-portrait.png',
ipadPortraitx2: 'screen-ipad-portrait-2x.png',
// iphone portrait
iphonePortrait: 'screen-iphone-portrait.png',
iphonePortraitx2: 'screen-iphone-portrait-2x.png',
iphone568hx2: 'screen-iphone-568h-2x.png',
iphone667h: 'screen-iphone-667h.png',
iphone736h: 'screen-iphone-736h.png'
}
},
// A list of resources to be copied.
resources : {
android : [{
from : 'phonegap/res/files/android',
to : 'res'}
]
},
// Android-only integer version to increase with each release.
// See http://developer.android.com/tools/publishing/versioning.html
versionCode: function(){ return(1) },
// Android-only options that will override the defaults set by Phonegap in the
// generated AndroidManifest.xml
// See https://developer.android.com/guide/topics/manifest/uses-sdk-element.html
minSdkVersion: function(){ return(10) },
targetSdkVersion: function(){ return(19) },
// iOS7-only options that will make the status bar white and transparent
iosStatusBar: 'WhiteAndTransparent',
// If you want to use the Phonegap Build service to build one or more
// of the platforms specified above, include these options.
// See https://build.phonegap.com/
remote: {
username: 'your_username',
password: 'your_password',
platforms: ['android', 'blackberry', 'ios', 'symbian', 'webos', 'wp7']
},
// Set an explicit Android permissions list to override the automatic plugin defaults.
// In most cases, you should omit this setting. See 'Android Permissions' in README.md for details.
permissions: ['INTERNET', 'ACCESS_COURSE_LOCATION', '...']
}
}
})
Beginning with v0.4.1, phonegap.config.config
may be either a string or an object.
As a string, the file is copied directly, as with previous versions.
As an object with the keys template<String>
and data<Object>
, the file at template
will
be processed using grunt.template.
Gruntfile.js
// ...
phonegap: {
config: {
config: {
template: '_myConfig.xml',
data: {
id: 'com.grunt-phonegap.example'
version: grunt.pkg.version
name: grunt.pkg.name
}
}
// ...
_myConfig.xml
<?xml version='1.0' encoding='utf-8'?>
<widget
id="<%= id %>"
version="<%= version %>"
xmlns="http://www.w3.org/ns/widgets"
xmlns:gap="http://phonegap.com/ns/1.0">
<name><%= name %></name>
<!-- ... -->
</widget>
If you choose to set phonegap.config.icons
with one or more icon sizes, these files
will be copied into the appropriate directories to use as your app icon.
You may want to use this feature in conjunction with grunt-rasterize to generate the correctly sized icon files from an SVG source.
Currently this feature supports Android, Windows Phone 8, and iOS.
phonegap: {
config: {
// ...
icons: {
android: {
ldpi: 'icon-36-ldpi.png',
mdpi: 'icon-48-mdpi.png',
hdpi: 'icon-72-hdpi.png',
xhdpi: 'icon-96-xhdpi.png'
},
wp8: {
app: 'icon-62-tile.png',
tile: 'icon-173-tile.png'
},
ios: {
icon29: 'icon29.png',
icon29x2: 'icon29x2.png',
icon40: 'icon40.png',
icon40x2: 'icon40x2.png',
icon50: 'icon50.png',
icon50x2: 'icon50x2.png',
icon57: 'icon57.png',
icon57x2: 'icon57x2.png',
icon60: 'icon60.png',
icon60x2: 'icon60x2.png',
icon60x3: 'icon60x2.png',
icon72: 'icon72.png',
icon72x2: 'icon72x2.png',
icon76: 'icon76.png',
icon76x2: 'icon76x2.png'
}
}
// ...
}
}
The config-xml documentation from Phonegap Build (the remote build service)
indicate that you can set a versionCode for your AndroidManifest.xml
file inside your config.xml
. However, phonegap
just ignores that property.
Google Play will not allow you to upload more than one APK with the same versionCode
.
If you set a phonegap.config.versionCode
value (function or literal), grunt phonegap:build
will post-process the generated
AndroidManifest.xml
file and set it for you.
In most applications it should simply be an integer that you increment with each release.
See http://developer.android.com/tools/publishing/versioning.html
This option will be ignored for non-Android platforms or when using the remote build service.
When you use phonegap:release
to build an apk package for the Android platform,
grunt-phonegap
will post-process the phonegap-generated AndroidManifest.xml
file to set debuggable=false
, unless you set the phonegap.config.debuggable
option to true.
A debuggable package cannot be published to the Play store. If you want to generate
an unsigned, debuggable package for testing on your own devices, you can use the
phonegap:debug:android
task instead to do this.
This feature exists to ensure we get the intended behavior no matter what Phonegap version you are using. In Phonegap 4.3.x, the release apk is created with debuggable=true regardless of whether a debug certificate was used. In Phonegap 4.4.x, this has been corrected.
Some Android applications need to force a specific value for minSdkVersion
and targetSdkVersion
, for example to enable "quirks mode" in Android 4.4's Chrome-based WebView.
Supposedly, Phonegap Build supports this through a config.xml preference like this:
<preference name="android-targetSdkVersion" value="13" />
However, setting this preference appears to have no effect on the output during a local build.
If you set phonegap.config.minSdkVersion
and/or phonegap.config.targetSdkVersion
, grunt phonegap:build
will post-process the generated
AndroidManifest.xml
file and set it for you.
This option will be ignored for non-Android platforms or when using the remote build service. For remote Android builds, instead try the android-targetSdkVersion
preference mentioned above.
If phonegap.config.permissions
is omitted, plugin permissions will be set automatically by Phonegap. In most cases, this is what you want.
Ordinarily with Phonegap (local), permissions for the Android platform are written to AndroidManifest.xml
based on the requirements of the plugins that you have added to your project, so you do not have to worry
about them.
In some (perhaps unusual) situations, you may want to alter these permissions without modifying a plugin.
When you may want to do this:
- To reserve not-yet-used permissions during development
- To enable a plugin that does not require the right permissions for your target version of Android
- While troubleshooting a permissions error in your app.
- When using an advanced Grunt workflow to set your permissions for different builds dynamically (by specifying
phonegap.config.permissions
as a function)
If you need this feature, set phonegap.config.permissions
to an array of permission basenames, such as ['ACCESS_NETWORK_STATE'].
When phonegap.config.permissions
is set, all permissions added by Cordova + plugins will be removed, giving
you complete control over the permission manifest.
This means you need to explicitely add any permissions required by plugins, or your app will not work.
Be careful to check any permissions your plugins need before adding this feature to your app, and remember to update it when adding additional plugins later.
If you are using the Phonegap Build cloud service for the Android platform, this setting will have no effect.
If you need to specify the screen orientation for your app on the Android
platform, you may set a value for phonegap.config.screenOrientation
to cause
grunt-phonegap
to post-process the generated AndroidManifest.xml
and set
the correct value for you.
The value can be any one of the following strings:
- unspecified
- behind
- landscape
- portrait
- reverseLandscape
- reversePortrait
- sensorLandscape
- sensorPortrait
- userLandscape
- userPortrait
- sensor
- fullSensor
- nosensor
- user
- fullUser
- locked
For an explanation of these options, refer to the android:screenOrientation
section of in the Android developer guide.
This option will be ignored for non-Android platforms or when using the remote build service.
If phonegap.config.androidApplicationName
is a string or function, then it will be applied to the <application android:name />
attribute in your AndroidManifest.xml
.
This option should almost always be left undefined
. You will only need to set this if you are implementing a base plugin
(a Java class extending from android.app.Application
), for example to implement crash reporting with ACRA.
If you set phonegap.config.remote
to a subset of phonegap.config.platforms
, those platforms will be built remotely. This is still somewhat
experimental, and may not integrate with all local features.
If you use Phonegap Build, you should add your Phonegap App ID to your .cordova/config.json
file - otherwise each build will be treated as a new app toward your account quota.
Example: {"lib":{"www":{"id":"phonegap","version":"3.3.0"}}, "phonegap": {"id": 1234567}}
You can find the PhoneGap App ID in your PhoneGap Builds panel.
Running phonegap:build
with no arguments will...
- Purge your
phonegap.config.path
- Copy your
phonegap.config.cordova
andphonegap.config.root
files into it - Add any plugins listed in
phonegap.config.plugins
- ..and then generate a Phonegap build for all platforms listed in
phonegap.config.platforms
If you pass a specific platform as an argument (eg grunt phonegap:build:android
), the phonegap.config.platforms
array will be
ignored and only that specific platform will be built.
Note that by default the project will be built with phonegap local
but you can switch to cordova
, by setting the phonegap.config.cli
to cordova
. But it won't let you remote build on phonegap build servers.
After a build is complete, the phonegap:run
grunt task can be used to launch your app
on an emulator or hardware device. It accepts two optional arguments, platform
and device
.
Example: grunt phonegap:run:android:emulator
If you are using the Android platform, you can see the list of connected devices by running adb devices
.
The platform argument will default to the first platform listed in phonegap.config.platforms
.
Create a releases/ directory containing a signed application package for distribution.
Currently android
is the only platform supported by this task. You will need to create
a keystore file at phonegap.config.key.store
like this:
$ keytool -genkey -v -keystore release.keystore -alias release -keyalg RSA -keysize 2048 -validity 10000
The keytool command will interactively ask you to set store and alias passwords, which must match
the return value of phonegap.config.key.aliasPassword
and phonegap.config.key.storePassword
respectively.
Creates a releases/debug directory containing an unsigned application package with debugging enabled.
Currently android
is the only platform supported by this task.
By browsing to this APK asset from test hardware device, we can quickly install the APK output from our build. Then we use chrome://inspect to inspect the network traffic as an example - this is not possible using the signed APK.
Log into the Phonegap Build service with the credentials specified at phonegap.config.remote.username
and phonegap.config.remote.password
.
Log out of the Phonegap Build service.
git clone https://github.com/logankoester/grunt-phonegap.git
cd grunt-phonegap
npm install
git submodule init
git submodule update
grunt
Note that not all tests can be run on all platforms. For example, tests depending on the Windows Phone SDK will be skipped if your OS is detected to be non-Windows.
Fork the repo on Github and open a pull request. Note that the files in tasks/
and test/
are the output of
CoffeeScript files in src/
, and will be overwritten if edited by hand.
Likewise, README.md
is the output of the grunt docs
task, and will be overwritten. README updates should be made in
the Markdown files under docs/
.
Before running the included test suite, you must first run git submodule update --init
on your local clone (see above).
Please run grunt build
before submitting a pull request. The build output should be included with your changes.
You can find all the changelogs here.
- Adds grunt-init-phonegap project template to make it easier to start new projects
- Updates
async
andgrunt-contrib-nodeunit
dependencies
Copyright (c) 2013-2014 Logan Koester.
Released under the MIT license. See LICENSE-MIT
for details.