Going Mobile with Oracle JET
Part of the reason you should choose Oracle JET over other javascript frameworks is how easy it is to go mobile.
By that I mean turning your web application to a native mobile application where you can really tune it to use the the features of the device you’re targeting.
There are some gotchas along the way which I stumbled on and it took some time to work out what the problem was and subsequently how to solve it. Hopefully this post will help you out if you too are struggling.
This post will take you through the journey of taking a web application scaffolded in JETs navdrawer template and targeting my rather ageing iPhone without paying for a developer licence. You won’t be able to deploy to the app store but at least this way you can “try before you buy”.
Apple Developer Prerequisites
Developing an Apple means enrolling on the Apple Developer Program. For my investigation/testing I didn’t fancy paying this $99 and found that you can actually create a temporary one (expires in 7 days of creation).
First things first, startup Xcode and navigate to
Xcode > Preferences > Accounts tab
From here you can add your Apple ID by clicking on the + icon and choosing “Apple ID” from the popup.
Once that is added your Apple ID will show you as a member of Personal Team:
Click “Manage Certificates…” which opens up a popup.
Click + on this window and give yourself the “iOS Development” certificate.
This unfortunately doesn't conclude everything we need to do for a provisioning profile. One way I found useful after searching a few blogs was to create a new Xcode project.
We won’t be using this project but just setting one up to initialise the provisioning profile we need to sign the app.
- Open Xcode and go to File > New > Project.
- Select “Single View App”.
- In the next screen we need to provide some values
Product Name needs to match your Project name with dashes removed. For example my directory/project was named “web-to-mobile” which resolves to webtomobile. Set Team to be the account you just added through the Xcode preferences and enter “org.oraclejet”.
The Product Name and Organization Identifier values make up the Bundle Identifier as seen in the screenshot above. The Bundle Identifier needs to be the same as the widget id
attribute within the $project/hybrid/config.xml:
Click “Next” on the window.
You will be asked where to store your new project and if you want to “Create Git repository”. For Git we can uncheck the box and you can select a place where the unused project will be created:
Once your project is complete we get a provisioning profile created. You can check this has been created by using Terminal and change directory using the following command and view the contents of the folder:
cd ~/Library/MobileDevice/Provisioning\ Profiles
ls -altr
If you open your .mobileprovision file you will find your TeamIdentifier id:
Together with the id in the file name, you need the TeamIdentifier to sign your app. We will use these two values within the build-config file in the next step.
Adding Hybrid Source
ojet add hybrid
Yep! Thats all you need to run from within your JET project to get your project scaffolded for mobile.
Sidenote: There are some extra parameters you can add to this to make things easier such as --appName=”My New Cool App”
which is the name of the application on your emulator/device
The config file contains your iOS signing details. As mentioned in the developer guide you do not need this for Windows/Android development.
An example of this config file is below. Note I have put the filename of my provisioning file into “provisioningProfile” and the value from within that file into “developmentTeam”:
{
"ios": {
"debug": {
"codeSignIdentity": "iPhone Developer",
"provisioningProfile": "c8dc2d39-5de2-4bb3-bc26-c83ed6d119ac",
"developmentTeam": "R5CXVFCSDJ",
"packageType": "development"
},
"release": {
"codeSignIdentity": "iPhone Distribution",
"provisioningProfile": "70f699ad-faf1-4adE-8fea-9d84738fb306",
"developmentTeam": "FG35JLLMXX4A",
"packageType": "app-store"
}
}
}
For further information visit: http://cordova.apache.org/docs/en/6.x/guide/platforms/ios/index.html#signing-an-app
Note: If you haven’t got Cordova installed then you will get the following message when running that
Gotcha Alert: When running the above command I didn’t have correct access to the directory. As I found out to my peril, if this doesnt work then you will have problems further on down the line. So my hint here is not to fall back to using sudo but to sort out your directory and ensure that its under your Mac users permissions.
When you run this command you will get the option to choose your target. For Mac this is just iOS if its installed
Once finished you will get a “Add-hybrid finished” message:
When viewing whats happened to your project directory, you will notice you now have a hybrid, src-hybrid and src-web:
This looks a little daunting at first with so many directories so lets review these in turn:
- hybrid — This is the equivalent of your “web” folder. Its the folder that now contains your xcode project (hybrid/platforms/ios). It contains your compiled “web” folder plus any overrides from src-hybrid which is now your build output for your device (hybrid/www).
- src-hybrid — Think of this folder as an override directory for your mobile app. For example, if you want different html for certain views or different viewModel logic then this is where you want to drop it into. The file in this directory will completely override the file from your main “src” directory
- src-web — If you have come from developing a pure web application you are fully aware of the “src” and “web” directories. To understand the “src-web” folder takes a bit of a paradigm shift in thinking about your project structure; you are now working with essentially 2 source sets. Thats not to say that everything is duplicated and thats the great thing JET is trying to handle for you. The way to see the project now is your original “src” directory is your main code line, src-hybrid allows overrides for your mobile and src-web allows further overrides from your main code line for the web. Again, if you have come from a pure web app then you have nothing to do here but JET enables this folder as an extension point if/where necessary
Compiling to the Simulator
If you cd to $JET_PROJ/hybrid then you can run the cordova commands as required. You don’t need to do anything directly with cordova but its useful to know.
Such as when aiming your simulator to a particular device, you can check which emulators are installed (we will use this later):
cd hybrid
cordova run ios --list
Back to why we are here, you can run your web app on your emulator by simply running the following:
ojet serve ios
The default destination for the ios platform is the simulator and hence you do not need to provide that parameter. You also do not need to provide the build-config either which means its quite easy to get your app working on the simulator.
By default, my target seemed to be “iPhone X” which I didn’t like too much.
After some debugging of the JET build code, I found that you can target different devices on the emulator by providing it as part of the destination
flag after a semi colon after emulator
:
Important Sidenote: JET doesnt leave this kind of debugging for you to work out. I was curious to see how it was done to expand my learning of the build tool. There is the command ojet help
. For example help with serving your application you can run: ojet help serve
Running the following meant I could change the emulator device using one of the ones listed by the cordova list command previously mentioned:
ojet serve ios --destination=”emulator:iPhone-5s"
or
ojet serve ios --destination=”emulator:iPhone-SE"
or
ojet service ios --emulator="iPhone-SE"
Once running in the simulator you will see your app:
Deploying to Device
If you have got your “paid-for” developer provision then things are rosey from this point, you simply need to run:
ojet serve ios --destination="device" --build-config=mobileConfig.json
Gotcha Alert: But with a self created provision you get an error with running the above via command line because the profile is Xcode managed:
As much as I tried, and, without really understanding the Apple app deployment process, I found a few blogs that say its not supported to sign your app with cordova and a self provision any more.
However, not all is lost; we can use Xcode to finish the job here.
To reiterate, you only need to follow this method if you have created your free provision.
Navigate to your xcode project file $JET_PROJ/hybrid/platforms/iOS/$your_project_name.xcode
and double click on it to open it up in Xcode:
Once your Xcode is open with your project, click on the project name on the top left hand side where it opens up your projects options. You can see that there are errors by default. This is because there is no Team selected.
When changing the Team these errors disappear:
We could now run the build and the app will be deployed to the device.
However, after the app loads I got a solid white screen and an error in Xcode logs:
So this doesn’t work but what has happened here is that its set the automatic profiling for us. Now we can use cordova to launch that app.
So what I recommend now is that now you have changed the Team profile, close Xcode and run the JET script to finally deploy:
ojet serve ios — destination=”device”
Gotcha Alert: The first time you get your app onto your device you will receive a message similar to the following:
This is because your self signed provision is not trusted. You can trust this from your device by navigating to the following on your device:
Settings > General > Device Management > user > Trust user
Now you can either re-run the command or just try and run the app on the device.
There we have it, the app is finally on the device:
Gotcha Alert: I was having problems with my web application running in the mobile app on the device. The app was running fine in the simulator but the app just did not load the center ViewModel.
I finally traced the issue down to the knockout applyBindings within main.js. The reason why it was falling over was….I was using the URLPathAdapter and not the URLParamAdapter (Note: the urlPathAdapter is used by default if one is not defined). Once adding this line in the app loaded in the mobile
oj.Router.defaults[‘urlAdapter’] = new oj.Router.urlParamAdapter();
I used Safari on the Mac to connect to the device and debugged that way. Strangely, knockout wasn’t actually throwing any error messages but as soon as I narrowed down the area where the issue was a try..catch helped me:
try {
ko.applyBindings(app, document.getElementById(‘globalBody’));
} catch(e){
console.info(e)
}
This printed out to the safari console the true error and I was able to work out the core problem.
NOTE: I got this error because I came from a web application where I had used the path adapter for SEO purposes. Quick note then: if you’re on mobile, use the urlParamAdapter.
Status Bar Fix
Gotcha Alert: You might have noticed that the app fills the entire screen and that means taking over the status bar at the top where the strength bar, time etc all sit.
This is not really ideal as it overlaps and looks pretty ugly. However, a tip from Graeme Mawson @ Oracle solves this:
- Add a cordova plugin
- Add the config into the
$PROJ/hybrid/config.xml
file within the<platform name=”ios”>
section
So, first off lets install the plugin:
ojet add plugin cordova-plugin-statusbar
And then add the following lines into $PROJ/hybrid/config.xml:
<preference name=”StatusBarOverlaysWebView” value=”false” />
<preference name=”StatusBarStyle” value=”default” />
Here you can see I have added them underneath the pre-existing preferences:
Now rerun and deploy the app and voila, all fixed:
Final Thoughts
Its extremely complicated to get an application using Apple devices. This complication is made even harder by trying to use the free profile which means you jump through hoops to get something working.
Hopefully you can use this blog as a reference to test your applications on Apple devices for free to check them out before plunging for the Apple licences.
I’d spent a lot of time trying to avoid the use of Xcode as the idea of everything scripted was cool. However, the reality is that a free provision means this is not a possibility.
However, Oracle JET makes it insanely easily to get from a web app to mobile and hopefully by following this you can get it working a lot quicker than I did :)
Good Luck!