Category Archives: PhoneGap

Enable Debugging in Android Using PhoneGap Build

12 Nov 2016

PhoneGap Build offers easy iOS and Android builds without the need to install any SDK’s. To debug an app in iOS you simply create an Ad Hoc Provisioning Profile, upload it to PhoneGap Build, and then create your app. When its time to build for production you then provide a Distribution Provisioning Profile and PhoneGap Build creates your IPA ready for the App Store. On Android – you don’t have the option of providing a debug or release key as PhoneGap Build will always create a release build from the key that you provide.

In a normal PhoneGap CLI-based setup you would edit Android’s manifest.xml by adding the following attribute to the <application> element.

android:debuggable="true"

PhoneGap Build lets you edit the Android Manifest indirectly via a special-purpose element within the PhoneGap Build config.xml document. The element in question takes this form:


 

Any valid android manifest elements that you add within the above will have its attribute values over-ride its matching element’s attributes in the final manifest. In addition, if you provide an element within the above that doesn’t exist in the build’s manifest then that element will be inserted.

Since the android:debuggable attribute lives within the <application> element then all we need to do to enable debugging is the following:


    

In order for the above to work you **must** add the Android XML namespace to the widget element of your config.xml:

xmlns:android = "http://schemas.android.com/apk/res/android"

So then, a valid widget element would look like this:

The above was tested to work with PhoneGap Build CLI 6.3.0.

For additional information see the PhoneGap documentation.

For additional information re the Android manifest’s <application> element see the relevant documentation.

Loading an image from the iOS Library in PhoneGap

23 Aug 2016

While working through one of my personal projects I’ve figured out how to load an image from an iOS device’s Library. There are two steps – first use the Camera plugin to provide a UI for the user to select a file. The next is to take the file path the Camera plugin provides and use the File plugin to load it.

Requirements

This was tested via PhoneGap Build using the following setup:

  • CLI 6.3.0
  • iOS deploy target: 9.0.0
  • Camera plugin version 2.2.0
  • File plugin version 3.0.0

If you’re using PhoneGap Build this is what should be added to your config.xml





Using the Camera Plugin to Access the Library

It might seem counter intuitive to use the Camera plugin since it seems logical to first look at the File API to look for files… unlike the File API where you would need to write your own file browser and UI, the Camera Plugin uses native functionality and so makes it trivial to pick an image from a user’s Library. The Camera plugin will present a native UI to the end-user so that they can navigate their Library’s folder structure to locate the image they want to use and in the end provide a path to that image on the device.

This code will do what is described above:

   navigator.camera.getPicture(
      function (fileURI){
         console.log(fileURI);
         /* remove the comment below to use with
          * the rest of the code on this page
          */
         //convertPath(fileURI);
      },
      function (err){
         // fail
         console.log('fail',err);
      },
      {
         allowEdit: true,
         correctOrientation: true,
         destinationType: Camera.DestinationType.FILE_URI,
         sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
         targetHeight: window.innerHeight,
         targetWidth: window.innerWidth
      }
   );

Literally copy and paste the above, here are the things to note about the configuration object:

  • allowEdit – this is a flag that tells the native Library picker UI to allow scaling/positioning of the resource that the user selects.
  • correctOrientation – as it implies, use the image in the correct orientation relevant to how the device is being held
  • destinationType – this is the part that tells the plugin to return the path to the image
  • sourceType – tells the plugin to display UI to allow the user to select the image from the library
  • targetHeight – the desired height of the image – iOS creates a temporary image and passes that path back to you based on any edits and the Height and Width settings. Here I just assume that you would want an image that is the size of the viewport.
  • targetWidth – see above

That’s it. Dead simple. Now we need to load up the file using the path that the Camera plugin returns which requires the use of the File plugin.

Using the File plugin to Load an Image

This part is trickier and the source of much frustration among developers – during my search for documentation there was no single source that explained how this should work. I was left to putting the parts together from various sources as the “official” documentation didn’t directly explain how to do it. Anyway, I’ll do the explaining here within the code comments.

In short, these are the steps that result in a Base64 serialization of the image from which you can do whatever you like:

  1. Convert the image path to a file Entry Object
  2. Pass the FileEntry Object to a function that converts it to a File Object
  3. Pass the File Object to a FileReader to read the file
  4. Handle the response containing the image data

Here is all of the code:

   /**
    * This takes a file:// URI and creates a file entry object. The operation is asynch,
    * so the resulting fileEntry object is passed to the success callback.
    * @type {Function}
    * @name convertPath
    * @param {String} fileURI - the file:// path to the resource
    * @return {} Returns nothing
    */
    function convertPath(fileURI){
        window.resolveLocalFileSystemURL(
            fileURI,
            function(fileEntry){
                getFileSuccess(fileEntry);
            }
        );
    }

   /**
    * This starts the read process via the file entry object. This is asynch, so the file is passed to the success callback
    * @type {Function}
    * @name getFileSuccess
    * @param {Object} fileEntry - the file entry object
    * @return {} Returns nothing
    */
    function getFileSuccess(fileEntry){
        fileEntry.file(
            readFile, // success
            function(err){ // failure
                console.log('Failed to get file.',err);
            }
        );
    }

   /**
    * This creates a file reader using the file object that is passed to it.
    * Note how similar this is to programatically creating an image and loading data into it.
    * @type {Function}
    * @name readFile
    * @param {Object} file - file object
    * @return {} Returns nothing
    */
    function readFile(file){
    	console.log('got file...',file);
        var reader = new window.FileReader();
        reader.oneerror = function(e){
            console.log('FileReader Error: ',e.target.result);
        };
        reader.onloadend = function(fileObject) {
            console.log('we have the file:',fileObject);
            console.log('the image data is in fileObject.target._result');
        };
        reader.readAsDataURL(file);
    }

You can use the fileObject.target._result to populate the background of a div, for example:

$('#myDiv').css('background-image','url:(' + fileObject.target._result + ')');

Or insert it into a canvas:

   var image = new Image();
   var canvas = document.getElementById('canvas');
   var context = canvas.getContext('2d'); //retrieve context
   
   image.onload = function(){
      context.drawImage(this, 0, 0,_canvas.width, _canvas.height);
   }
   image.src = fileObject.target._result; // load the image data

It’s worth noting that of course you’ll need the appropriate styling for your DIVs if using the resulting image data as a background image. Also, if loading the data into a canvas your aspect ratio may be off – you’ll need to figure out how to scale the data to fit the canvas without distortion.

Create Mobile Provisions and P12 files without a Mac for Cloud Build Services

02 Aug 2016

There are many Windows developers who want to create iOS apps but do not want to make the investment into Apple hardware – one way around it is to virtualize OSX which works OK if your intent is to use Xcode. The other option is the situation where you are planning on using cloud services to build a hybrid app. The great thing about building in the cloud is that you don’t have to have Apple hardware to do so. A barrier that you’ll encounter very quickly is that you need two files to build in the cloud: 1) a Mobile Provision File and 2) a P12 file.

NOTE: Some cloud build services don’t submit the app for you (i.e., PhoneGap Build) while others do (i.e., Ionic’s app workflow). In the former case a Mac will be needed to upload your distribution IPA (your compiled app) to Apple. The instructions on this page will allow you to create files for development and production purposes without needing a Mac.

Being a Windows guy (and to be honest, an Android one as well) that didn’t help me much until I realized that I could do everything without a Mac using OpenSSL.

What follows are all the steps that anyone will need to be able to use a cloud build service to build a hybrid PhoneGap app for both development and distribution.

As a bonus this article wraps things up with instructions on how to use the Application Loader to upload and then submit your app to the App Store.

Install Open SSL

To begin, download and install these two pieces of software:

Install the Microsoft product first, then install OpenSSL.

Add OpenSSL to Your Environment Path

I tried to add the c:\OpenSSL-Win32\bin folder to my environment path but had some issues with it. In the end what I did was to execute everything within the bin folder (as described below) and created a naming convention so that all of the files that I created would stay grouped together at the top of the folder. Specifically, since I was creating everything for development purposes, I used the “_dev” prefix. When I was done it was easy to see all the files.

Well, that was my personal preference – you can come up with your own naming conventions…

Create a Certificate Signing Request

If you installed OpenSSL to its default location then navigate to:

  • C:\OpenSSL-Win32\bin

Once in that directory press SHIFT and RIGHT-CLICK in the Explorer window showing that directory. A menu will appear – click on “Open command window here”.

Your currently using the Windows command prompt, type the following and press “enter” to switch to the OpenSSL prompt:

  • openssl

You will get a warning message when you do this, below is an example of typing in the openssl command and the result:

C:\OpenSSL-Win32\bin> openssl
WARNING: can’t open config file: /usr/local/ssl/openssl.cnf
OpenSSL>

The warning is normal and can be ignored. Enter the following command to create a key substituting the name of the key for your desired key name.

  • genrsa -out mykey.key 2048

Next use this command to create your CSR (Certificate Signing Request), be sure to replace the email, name, etc with the proper values:

  • req -new -key mykey.key -out mycertificate.csr -subj “/emailAddress=your@address.com, CN=Joe Smith, C=US” -config “openssl.cfg”

All done, your CSR is in the bin directory. If you followed the above instructions verbatim then your file is called mycertificate.csr. Below is a screen capture of the above console steps.

openssl

Next you need to upload your CSR to the Apple Developer Portal.

Login, click “All” under the “Certificates” heading and then click the “+” (plus) button to begin the upload process. Click continue/next, etc until you see this screen:

cert_upload

Upload your CSR. If successful you will see the next image. If not then recreate your CSR and try again.

cert_ready

Click the “Download” button to download the “ios_development.cer” file <<< make note of this file as you will need it in a moment. Move this file to the c:\OpenSSL-Win32\bin directory if you are executing your OpenSSL commands from that location.

Add Devices

Before you create a Mobile Provision: In order to be able to install your app on to development devices you need to register them in the developer portal. Again, within the Developer portal click the “All” link under the “Devices” category and then enter the desired name of the device and its UDID.

Create a Mobile Provision file

This time in the Apple Developer Console click “All” under “Provisioning Profiles” then:

  1. Click the “+” icon
  2. Select the appropriate type of provision – in my case it is “iOS App Development”
  3. Click “Continue”
  4. Select the appropriate App ID
  5. Click “Continue”
  6. Select the appropriate Certificate
  7. Click “Continue”
  8. Select the development devices that you want to work with your profile
  9. Click “Continue”
  10. Give your profile a name
  11. Again, click “Continue”…

The provisioning profile has been created, download it and keep it in a safe place as you will need to upload it to your cloud build service (1 of 2 files that you need for that purpose).

P12 Certificate

Along with the Mobile Provision file the P12 (also known as a PFX) is provided to cloud build services to build your iOS app. A P12 is a combined format that holds both the private key and the certificate.

Before you can create the P12 file you have to convert the certificate that Apple provides you after you’ve uploaded the CSR to a PEM file.

To convert the Apple-provided “CER” file (previously referred to as the “ios_development.cer” file) to a PEM:

  • x509 -in ios_development.cer -inform DER -out developer_identity.pem -outform PEM

Where:

  • ios_development.cer is the CER file you downloaded from Apple
  • developer_identity.pem is the desired name of your PEM file

When you issue the above command you will have a “PEM” file in your bin folder. Next you’ll convert that to a P12/PFX using this command:

  • pkcs12 -export -inkey mykey.key -in developer_identity.pem -out my_p12.p12

Where:

  • mykey.key is your key file
  • developer_identity.pem is the PEM file created in the previous step
  • my_p12.p12 is the desired name of your P12 file

Note that:

  • You will be asked for the “Export Password” when creating the P12
  • You will be asked to verify the password

Look for your P12 in the bin folder. That file along with your Mobile Provision file are the files your cloud build service will need to compile your apps. Also, take this moment to write down the password you used for your P12!!


Creating an App Store Production Certificate & Provisioning Profile

PhoneGap Build does a great job of creating IPA’s that you can side-load via iTunes to your i-device. Eventually you’ll be ready to submit your app to the App Store. To do so you repeat the steps that you took to create all the needed files for development, just be sure to choose options relevant for submission to the App Store.

As an aside, Ionic’s workflow now includes direct submission of your apps to the Apple App Store – no Mac needed! In the scenario described in this blog post, however, you **do** need a Mac to submit your app. I recommend finding a friend with a Mac instead of shelling out $$$ to buy one. Or if you’re the adventurous type go ahead and check out Ionic.

Back to the topic at hand – you will *** REPEAT *** all the steps above and only change a couple of things. You will choose options specifically for distributing your app. These two differences are described in the next two sections.

Create App Store Distribution Certificate

As before, follow the same process for creating the Certificate. There is one key difference – you will choose the “App Store and Ad Hoc” option as noted in these steps:

  1. Log into the Apple Developer Portal
  2. Click “Certificates, Identifiers & Profiles”
  3. Click the “+” icon
  4. The “What Type of Certificate do you need?” screen appears. Under the “Production” heading choose “App Store and Ad Hoc
  5. The next screen is titled “About Creating a Certificate Signing Request (CSR)”. Click the “Continue” button
  6. The next screen is titled “Generate Your Certificate” – on this page you will upload the CSR that you created earlier. Go ahead and upload and the Distribution Certificate will be created. Download it and keep it in a safe place.

Create a Distribution Provisioning Profile

Again, you’ve already done this for your development files – repeat them here but choose “App Store” where appropriate:

  1. Log into the Apple Developer Portal
  2. In the left column under “Provisioning Profiles” click on “Distribution”
  3. Click the “+” icon
  4. This page is titled “What type of provisioning profile do you need?” – choose “App Store“, then click “Continue”
  5. The next screen is the “Select App ID” screen. Choose the bundle identifier relevant to your app then click “Continue”
  6. The next screen is titled “Select certificates” – choose the certificate that you created previously. Click the “Continue” button
  7. Next is the “Name this profile and generate” screen – give the profile a meaningful name then click “Continue” to generate your Distribution Provisioning Profile

Build the Production IPA in the Cloud

Log into PhoneGap Build, add your new files (select “Add a key” in the iOS “key” drop down list) and do a build against it. Since the files you are providing are distribution files you will automatically get a distribution IPA as a result. Download the production-ready distribution IPA to the Mac that you will use to submit your app to the App Store.

Upload Your Distribution-Ready App to the App Store

On the Mac make sure that Xcode is installed then start the Application Loader – in the screen shot below I typed “Application Loader” into the finder to locate the application.

submit_to_app_store_1

Enter your Apple ID and Password:

submit_to_app_store_2

Click “Choose” and browse for your Distribution-ready IPA file:

submit_to_app_store_3

Once your app is checked for conformance to submission rules you will see the “Deliver Your App” window. Click the “Next” button to submit the app.

submit_to_app_store_4

The “Deliver Your App” window appears where you can see the progress of your app while it is being submitted to the App Store. To view details of the process click the “Activity” button. Otherwise, just sit back and be patient.

submit_to_app_store_5

The deliver your app screen appears, click “next” to deliver your app. The process took about 2 or 3 minutes for my app to get through the submission process before I was finally greeted with this screen:

submit_to_app_store_6

Click the “Next” button to see the “Thank You” screen:

submit_to_app_store_7b

Submit Your App to the App Store

You must add a new app to the iTunes Connect Portal, including all the needed information, screen captures, icon art, etc before you can submit your app to the App Store. Once you have that done, then you can submit your app using the following steps.

  1. Log in to iTunes Connect.
  2. Click “My Apps”
  3. Click your app to view its details
  4. Click on “Prepare for Submission”
  5. Click “Build” to select your build
  6. Select the build from the list that appears
  7. Click the “Save” button
  8. Click “Submit for Review”

PhoneGap / xCode Transport Security Error

18 Jan 2016

Debugging a PhoneGap project we needed to be able to see the database so we ran the emulator via xCode and tried using Safari to remotely inspect the webview. This worked but Safari would’t show us the database. We then tried to use Weinre so that we could use Chrome to do the remote inspection but xCode complained with the following error:

Screen Shot 2016-01-18 at 3.21.17 PM

App Transport Security has blocked a cleartext http (http://) resource load since it is insecure. Temporary exceptions can be configured via your app’s Info.plist file.

The error message told us what to do to work around the issue and a few seconds later we found the answer on Stackoverflow – add this to the plist.

NSAppTransportSecurity

  
  NSAllowsArbitraryLoads
      

Transport security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app’s Info.plist file.

That’s it – Weinre worked and we moved on….

Bootstrapping Angular in Cordova

16 Oct 2015

Creating hybrid apps means almost all of your time is spent in Chrome doing layout, development, testing, etc. When it comes time to start integrating your app into PhoneGap/Cordova you have to take into account a device’s deviceready event but doing so breaks your app outside of the Cordova wrapper.

One option is to automate your builds using Gulp. If you’re adverse to this you can try the following bit of code which will allow you to easily switch from your desktop to device:

        ;(function(){
            function bootstrapNG(){
                angular.bootstrap(document.querySelector('html'), ['name-of-your-app']);
            }
            if (document.location.href.indexOf('http') === -1){
                document.addEventListener('deviceready', function(){
                    angular.element(document).ready(bootstrapNG);
                }, false);
            } else {
                angular.element(document).ready(bootstrapNG);
            }
        })();

This works because the assumption is that as a dev you will be running a local server to run your app whereas in Cordova/Phonegap the app is running directly off of the file system so that URL is not using an HTTP:// scheme but is instead using file://.

Note that manually bootstrapping Angular will require you to remove the ng-app directive from your page.