Dienstag, 15. November 2016

Oracle Jet Hybrid-Application --- Enable Remote Debugging


Introduction

While I have been developing the mobile hybrid application with Oracle Jet, I have been realizing, that I couldn't do remote debugging. I did deploy the application on my Android Virtual Device and did set some breakpoints. Useless.

I did make some research and was able to find a solution with Google Chrome. Make the following steps, if you also want to be able to remote debug your Oracle Jet application, running on an Android Virtual Device.

Enable USB Debugging on Android Virtual Device

  • Start your Android Virtual Device
  • Go to the Settings of the device
  • Click on Developer Options (check here, if not visible)
  • Enable USB Debugging


Do standard deployment of your Oracle Jet hybrid application
$ grunt serve:dev --platform=android --destination=emulator-5554


Enable Remote Debugging with Chrome

We did place an onclick listener on the Start game button. Now what we are doing is connecting the Chrome browser to the Virtual Devices and setting a breakpoint in Javascript.
Start Chrome and press F12




Now click the Escape (ESC) key to enter developer mode in Chrome





Now select Remote devices





Now you have a look at all the connected Remote devices. There is a lot of information about your connections and the connected devices.
  • On the left side you can see your Android Virtual device. Select it.
  • Now you see all the hybrid apps on your Android Virtual Device
  • Select the app you are about to debug and click on Inspect





A new window is being opened.
  • Click on Sources to see all the Javascript files
  • Now set a breakpoint in the Javascript function
  • After clicking on Start game, the breakpoint should stop at your Javascript


Conclusion

This is a very nice and easy way to debug your application. But it can't only be used to Debug your application. You can also use it to make quick CSS changes, HTML changes or Javascript changes. Definitely a very useful tool for a productive development of hybrid applications.

Sonntag, 6. November 2016

Google Login with Oracle Jet - Part 3 - Combine with Oracle Jet hybrid application

Introduction


This is part 3 of a series of blogs, that explain on how to use Google Sign In with Oracle Jet. For more information, please start with part 1.
  1. Google Login with Oracle Jet - Part 1 - Create Google Project
  2. Google Login with Oracle Jet - Part 2 - Combine with Oracle Jet webapplication
  3. Google Login with Oracle Jet - Part 3 - Combine with Oracle Jet hybrid application
Let's continue with the fun part. After creating a Google project and an OAuth client ID in part 1. We did create a basic Oracle Jet webapplication and added a Sign In and Sign Out functionality to it. In part 3 of this blog series, we want to do the same as we did in part 2 with the difference that we implement a hybrid application for our smartphone, instead of implementing a webapplication, as we did in part 2.


Create Oracle Jet hybrid application

We did this several times before and we will do it again. We will create really fast an Oracle Jet page, which is based on the navdrawer template. Just enter the following commands to first create it an than build it.

$ yo oraclejet:hybrid hybridclient --appid=de.lumabit.googlelogin --appname=googlelogin --template=navdrawer:hybrid --platform=android

$ grunt build --platform=android

Add Google+ cordova plugin

I did checkout the cordova page to find a plugin, which is suitable for using a Google+ login. I did decide to use the following plugin and didn't have any problems so far with my android virtual device and my nexus 5. I didn't test with any other android device or with the iphone yet.

https://www.npmjs.com/package/cordova-plugin-googleplus


It is not needed to follow the Cordova documentation. Everything needed to make it work with OracleJet is included in this blog.

The good thing about Oracle Jet is, that you don't have to explicitly download the cordova plugin, if you want to use it. All you have to do is open the following file with your NetBeans IDE

hybrid/config.xml


and add the following lines code to the config.xml

<plugin name="cordova-plugin-googleplus" spec="https://github.com/EddyVerbruggen/cordova-plugin-googleplus">
    <variable name="REVERSED_CLIENT_ID" value="<Reverse_GoogleLogin_Web_ClientID>" />
</plugin>



Reverse_GoogleLogin_Web_ClientID has been created in part 1 of this series of blogs and should be used in reversed form here.
This means it should look similar to this: com.googleusercontent.apps.<LONG_UNIQUE_ID>

ATTENTION: It is very important that you use the OAuth2 webapplication id here and not the OAuth2 Android id, which will be created later.

If you don't remember your GoogleLogin_Web_ClientID it can be found here:
https://console.cloud.google.com/apis/credentials



Create the Javascript functionality

We do need some Javascript functions like GoogleSignIn, GoogleSignOut or IsUserLoggedIn to make this work.
Please open the profile.js file and make the following adjustments  to it.

1. First of all we have to extend the define, because the ojs/button also has to be loaded. So please add 'ojs/ojbutton' to your define.

My define looks like this now. Yours can look different, but the important part is, that you add this 'ojs/ojbutton'

define(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojbutton'],
        function (oj, ko, $) {



2. Create the knockout observable parameters, that will be used to define wether the user is logged in or not and the imageUrl of the user
// Define if the user is logged in
self.isUserLoggedIn = ko.observable(false);
// Image Url
self.imagePath = ko.observable("");




3. We write a function, which will be triggered, when the user is clicking the sign in button. 
  • This is a promise, which is entering the first function, if everything worked fine and the second function, if there was an error.
  • In case of a success I decided to set isUserLoggedIn to true and set the imagePath of the user profile. The returned obj also contains other profile information. 
    • obj.email
    • obj.userId
    • obj.displayName
    • obj.familyName
    • obj.givenName
    • obj.imageUrl
    • obj.idToken
    • obj.serverAuthCode
  • In the second function, which means, that the login failed, we set the isUserLoggedIn to false again. We also give an alert to the user, telling what went wrong.
  • GoogleLogin_Web_ClientID has been created in part 1 of this series of blogs

function ProfileViewModel() {
...
self.googleSignIn = function (data, event) {
                    window.plugins.googleplus.login(
                            {
                               'scopes': 'profile email', 
                               'webClientId': '<GoogleLogin_Web_ClientID>', 
                               'offline': true 
                            },
                            function (obj) {
                               self.isUserLoggedIn(true);
                               self.imagePath(obj.imageUrl);
                               alert(JSON.stringify(obj));
                            },
                            function (msg) {
                                self.isUserLoggedIn(false);
                                self.imagePath("");
                                alert('error: ' + msg);
                            }
                    );
                }
...
}



4. We write a function, which will be triggered, when the user is clicking the sign out button. 
  • In case of a sign out success we do set isUserLoggedIn to false

function ProfileViewModel() {
...
self.googleSignOut = function (data, event) {
                    window.plugins.googleplus.logout(
                            function (msg) {
                                self.isUserLoggedIn(false);
                                self.imagePath("");
                            }
                    );
                }
...
}




5. We write a silentLogin function, which will be triggered, when the user enters the profile module. To make this possible we place the function call inside self.handlActivated(). Silent login sets isUserLoggedIn to true if the application already has the necessary rights to access the user profile.
  • This is a promise, which is entering the first function, if everything worked fine and the second function, if there was an error.
  • In case of a success I decided to set isUserLoggedIn to true and set the imagePath of the user profile
  • In the second function, which means, that the login failed, we set the isUserLoggedIn to false again.
  • GoogleLogin_Web_ClientID has been created in part 1 of this series of blogs

function ProfileViewModel() {
...
self.handleActivated = function (info) {
                    window.plugins.googleplus.trySilentLogin(
                            {
                               'scopes': 'profile email', 
                               'webClientId': '<GoogleLogin_Web_ClientID>', 
                               'offline': true 
                            },
                            function (obj) {
                                self.isUserLoggedIn(true);
                                self.imagePath(obj.imageUrl);
                                self.userObject = obj;
                            },
                            function (msg) {
                                self.isUserLoggedIn(false);
                                self.imagePath("");
                            }
                    );
                };
...
}


Trigger the Javascript functions from HTML

Open the profile.html file and make the following adjustments.

1. Add Sign In button and make it only visible, if the user is not logged in

<div data-bind="ifnot: isUserLoggedIn">
        <button id="google-signin-button"
                data-bind="click: googleSignIn, ojComponent: {
          component:'ojButton', label: 'Sign In',
          icons: {start:'oj-fwk-icon oj-fwk-icon-signin'},
          chroming: 'full'
        }">
        </button>
</div>






2. Add a Sign out and Disconnect button and make it only visible, if the user is logged in. Also add an image of the logged in user.

<div data-bind="if: isUserLoggedIn">
<button id="google-signin-button"
data-bind="click: googleSignOut, ojComponent: {
 component:'ojButton', label: 'Sign Out',
 icons: {start:'oj-fwk-icon oj-fwk-icon-signin'},
 chroming: 'full'
}">
</button>
<img data-bind="attr:{src: imagePath}" />
</div>







Deploy to Android (Virtual) Device

One last step that has to be done is, that we have to deploy our hybrid application to an Android device. The deployment is not the difficult part, but what has to be done, to give the deployed application access to the Google API is, that we have to create another OAuth2 id at the Google Platform. Besides the OAuth2 id for webapplications, we also need one for Android our applications. So what we do is, the following.

1. Open a cmd prompt and enter the following
$ keytool -exportcert -keystore C:/Users/<USERNAME>/.android/debug.keystore -list -v

<USERNAME> is your Windows username
If this is not working, than please check if the file debug.keystore does exist at that location

The password will be android


Now you should see all the entries in the keystore. You should also be able to see a SHA1 key. Please copy that key.





2. Go to the following URL

And create a new OAuth2 client ID for Android applications



3. Enter the needed information for the key

Name: Choose whatever you want
Signing-certificate fingerprint: Please take the SHA1 fingerprint that you copied two steps ago
Package-Name: Choose the package name, that you also picked in your hybric/config.xml file as the id of the widget. In my case it is de.lumabit.googlelogin



This is it. Now you are ready to deploy to your android virtual device.

Conclusion

This series of three blogs showed me, that Oracle Jet is working very well together with other vendors like Google or Cordova. It was possible to make this work without any crazy hacks. All that had to be done, was follow the standard tutorials. This is something I like. :-)

Sonntag, 23. Oktober 2016

Google Login with Oracle Jet - Part 2 - Combine with Oracle Jet webapplication

Introduction


This is part 2 of a series of blogs, that explain on how to use Google Sign In with Oracle Jet. For more information, please start with part 1.
  1. Google Login with Oracle Jet - Part 1 - Create Google Project
  2. Google Login with Oracle Jet - Part 2 - Combine with Oracle Jet webapplication
  3. Google Login with Oracle Jet - Part 3 - Combine with Oracle Jet hybrid application
Let's begin with the fun part. We did create a Google project and an OAuth client ID in part 1. Now we will create a basic Oracle Jet webapplication and add Sign In and Sign Out functionality to it. Besides that, we also want to read the name of the logged in user and show the picture of the logged in user.


Create Oracle Jet webapplication

We did this several times before and we will do it again. We will create really fast an Oracle Jet page, which is based on the basic template. Just enter the following commands to first create it an than build it.

$ yo oraclejet webclient --template=basic:web

$ grunt build

First steps

I did call it first steps, because I didn't find a better word and cause I didn't want to put these steps in another chapter.

1. Open Netbeans
2. Open the project which you just created
3. Create the following file
File-Location:
src/js/googlecredentials.json

File-Content:
{
    "client_id": "<LONG_UNIQUE_ID>.apps.googleusercontent.com",
    "scope": "profile email"
}

As you can see this is a JSON file, which holds the client_id. I am pretty sure, that it is not a good idea to keep your client_id here, because now everybody can read it, but I didn't find a better place to put it.

As client_id you should use the id, which has been created in Part 1 of this series of blogs. 
Go to the following URL, select your project and select Credentials (left navigation bar). Now you should be able to see your client Id again.



4. Make adjustments to the main.js file to read the googlecredentials.json file and store it in the sessionStorage as soon as the page is being loaded. The adjustments should be made in the init() function. As you can see, the credentials are being stored in an item called googlecredentials.

$.ajax({                                
url: 'js/googlecredentials.json',
dataType: 'json',
async: false,
success: function (data) {
sessionStorage.setItem('googlecredentials', JSON.stringify(data));
},
error: function (req, status, err) {
console.log('something went wrong', status, err);
}
});


Create the Javascript functionality

We do need some Javascript functions like GoogleSignIn, GoogleSignOut or IsUserLoggedIn to make this work.
Please open the appController.js file and make the following adjustments  to it.

1. First of all we have to extend the define, because the GoogleApi also has to be loaded. So please add 'https://apis.google.com/js/platform.js' to your define.

My define looks like this now. Yours can look different, but the important part is, that you add this 'https://apis.google.com/js/platform.js'

define(['ojs/ojcore', 'knockout', 'ojs/ojknockout', 'https://apis.google.com/js/platform.js'],
        function (oj, ko) {


2. Create some knockout observable parameters, that will be defined later
// Define if the user is logged in
self.isUserLoggedIn = ko.observable(false);
// Username
self.userLogin = ko.observable("");
// User Profile Picture
self.imagePath = ko.observable("");


3. Send the Client_ID to the GoogleApi and in return you get information about the logged in user, if the user is logged in. 
  • As you can see, here we send the googlecredentials.json that has been stored in the sessionStorage during the init() function of main.js.
  • We also redefine the isUserLoggedIn();
  • Since this function is placed directly inside the ControllerViewModel it will be called whenever the index.html is being loaded.

function ControllerViewModel() {
...
window.gapi.load('client:auth2', function () {                    
window.gapi.auth2.init(JSON.parse(sessionStorage.getItem('googlecredentials'))).then(function (googleAuth) {
self.googleAuth = googleAuth;
self.isUserLoggedIn(googleAuth.isSignedIn.get());
});
});
...
}



4. We write a function, which will be triggered, when the user is clicking the sign in button. 
  • This is a promise, which is entering the first function, if everything worked fine and the second function, if there was an error.
  • In case of a success I decided to set isUserLoggedIn to true and get some user profile information like picture and name.
  • In the second function, which means, that the login was not correct, we set the isUserLoggedIn to false again. Later we will see in the html, that different parts of the page will be shown, depending on this variable.

function ControllerViewModel() {
...
self.googleSignIn = function (data, event) {
window.gapi.auth2.getAuthInstance().signIn().then(
function () {
self.isUserLoggedIn(true);
self.userLogin(self.googleAuth.currentUser.get().getBasicProfile().getName());
self.imagePath(self.googleAuth.currentUser.get().getBasicProfile().getImageUrl());
self.id_token = self.googleAuth.currentUser.get().getAuthResponse().id_token;
},
function (e) {
self.isUserLoggedIn(false);
console.log(e);
});
}
...
}



5. We write a function, which will be triggered, when the user is clicking the sign out button. 
  • This is a promise, which is entering the first function, if everything worked fine and the second function, if there was an error.
  • In case of a sign out success We do reset all the user profile informatoin.
  • In the second function, which means, that the sign out was not correct, we just log the exception.

function ControllerViewModel() {
...
self.googleSignOut = function (data, event) {
window.gapi.auth2.getAuthInstance().signOut().then(
function () {
self.userLogin('Unknown');
self.imagePath('');
self.isUserLoggedIn(false);
},
function (e) {
console.log(e);
});
}
...
}




6. We write a function, which will be triggered, when the user is clicking the Disconnect button. The difference between disconnect and sign out is the following. A sign out is just signing out the user from your webapplication. A disconnect is also removing all the rights, that the user gave you. Disconnect is hardly used in this world, but quite interesting for development.
  • This is a promise, which is entering the first function, if everything worked fine and the second function, if there was an error.
  • In case of a disconnect success We do reset all the user profile informatoin.
  • In the second function, which means, that the disconnect was not correct, we just log the exception.

function ControllerViewModel() {
...
self.googleDisconnect = function (data, event) {
window.gapi.auth2.getAuthInstance().disconnect().then(
function () {
self.userLogin('Unknown');
self.imagePath('');
self.isUserLoggedIn(false);
},
function (e) {
console.log(e);
});
}
...
}


Trigger the Javascript functions from HTML

Open the index.html file and make the following adjustments.

1. Add Sign In button and make it only visible, if the user is not logged in

<div data-bind="ifnot: isUserLoggedIn">
<h1>Google Login --- Not LoggedIn</h1>
<button id="google-signin-button"
data-bind="click: googleSignIn, ojComponent: { 
component:'ojButton', label: 'Sign In',
icons: {start:'oj-fwk-icon oj-fwk-icon-signin'},
chroming: 'full'
}">
</button>
</div>





2. Add a Sign out and Disconnect button and make it only visible, if the user is logged in. Also add an image of the logged in user.

<div data-bind="if: isUserLoggedIn">
<h1>Google Login --- LoggedIn</h1>
<button id="google-signout-button"
data-bind="click: googleSignOut, ojComponent: {
component:'ojButton', label: 'Sign Out',
icons: {start:'oj-fwk-icon oj-fwk-icon-signin'},
chroming: 'full'
 }">
</button>
<button id="google-signout-button"
data-bind="click: googleDisconnect, ojComponent: {
component:'ojButton', label: 'Disconnect',
icons: {start:'oj-fwk-icon oj-fwk-icon-signin'},
chroming: 'full'
 }">
</button>
<img data-bind="attr:{src: imagePath}" /> 
</div>




3. Add the username to the page

This is the easiest part. Thanks to the nice basic template of the Oracle Jet webapplication, all we had to do was make updates to the self.userLogin observable, after the sing in has been successfull. Inside the HTML, we didn't have to do any adjustments.




4. Also make the Sign Out link in the upper right corner of the Oracle Jet basic template work.

Add a data-bind to the existing link.

<li id="out"><a data-bind="click: googleDisconnect" href="#">Sign Out</a></li>




Conclusion

As already mentioned in the introduction, it is way more fun to do this, than taking care of all the administrative stuff. 

In the end it is a solution, that makes your user happy, because, they don't have to remember a new username/password combination and it makes you happy, because you don't have to take care of usermanagement.

You also get the id_token of the user, which opens you a whole new world to the Google world (YouTube, Maps, ...). This is basically just the beginning. And it is working like a charme with Oracle Jet, because both Google and Oracle support OAuth2.0.

In the following blog, we will take a look on how to make this work with a hybrid application. We will need a cordova plugin for that.

Google Login with Oracle Jet - Part 1 - Create Google Project

Introduction

Our goal in this series of three blogs is to make Google Login available with an Oracle Jet webapplication and with an Oracle Jet hybrid application.



Android Virtual Device - Oracle Jet Hybrid application




Chrome Browser - Oracle Jet WebApplication - Not Logged In - User Clicks Sign In



Chrome Browser - Oracle Jet WebApplication - Not Logged In - User has to give access rights to the webapplication




Chrome Browser - Oracle Jet WebApplication - User is logged in - Profile information (name, picture) available and user can sign out.



In this and the following two blogs we will talk about the following

  1. This blog (Google Login Part 1 blog): Create Google Project and OAuth2 ClientID
  2. Google Login Part 2 blog: Make Google Login with Oracle Jet Webapplication work
  3. Google Login Part 3 blog: Make Google Login with Oracle Jet hybrid appliation work

Create Project

If we want to use the Google Login mechanism, we have to create our own project on the Google cloud console.

1. Enter the following URL and click on Create Project

Choose whatever name you want for the project




Enable Google+ API

If we want to use the Google Login mechanism, we have to use the functions of the Google+ API. That's why we have to enable it next.

2. It usually takes a minute until the project is created. You will automatically get forwarded to the following page, after the creation of the project is finished.




Click on enable and Mange API






3. Now click on Library (left navigation bar) and after that click on Google+ API






4. Click on Enable




Create OAuth2 ClientID

The client ID is needed to allow the communication between the Oracle Jet webapplication and the Google+ API.

5. Do the following steps
  • Click on Credentials (left navigation bar)
  • Click on Create Credentials
  • Select OAuthClientID




6. Fill out the form with the following values
  • Application Type: web application
  • Name: [WHATEVER_NAME_YOU_WANT]
  • Authorised Javascript origins: Here you have to add all the webpages that should be allowed to use this clientId
    • http://localhost
    • http://localhost:8383 [Oracle Jet local server]
    • http://[YOUR_PRODUCTIVE_DOMAIN]
  • Click on Create






7. An OAuth 2.0 Client ID has been created and should be visible. 
It has the format [LONG_UNIQUE_ID].apps.googleusercontent.com

ATTENTION: This id will be needed in the future. I will reference to it as the GoogleLogin Web ClientID








Other

8. As the last step you have to click on OAuth consent screen. Here you have to define the application name that will be visible to the enduser, when he has to give the rights to your app. (Checkout first picture in this blog as example - Android virtual device screenshot)

Enter as Product name whatever you want


Conclusion

Now after creating a Google project and an OAuth client id for our project we can move on to the next blog, which will tell us how to use this client id to make Google Login possible with Oracle Jet webapplication. 

Montag, 3. Oktober 2016

Enable Debug and LiveReload functionality in OracleJet Android application

Introduction

OracleJet YeoMan Generator: version 1.1
OracleJet: version 2.1.0

Debug and LiveReload (aka HotDeployment) are two very powerful functions. You should always try to make this possible in your development environment, no matter what framework you are using. Debug saves you a lot of time in finding bugs and LiveReload allows you to see your changes to the sourcecode after seconds instead of waiting for another redeployment, which can take minutes.

What is going on behind the scenes


To make this happen, there is a lot going on. But don't worry, all of this is already setup. The only thing you have to do is setup an Google Android Virtual Device, start the Virtual Device and run the following scripts.

To find out the name of your Virtual Device
$ adb devices

To start the process, that is pointed out in the picture above
$ grunt serve:dev --platform=android --destination=<NAME_OF_YOUR_AVD_DEVICE>

Here comes an explanation of the steps, shown in the picture
  1. Your source code is being build and moved to the hybrid folder, which contains the informatione needed to make cordova work
  2. A server is being started on your local machine with port 8000. It is important, that this server is running on port 8000. You can also check that this step has been working fine, by entering localhost:8000 in your browser. You should see something similar to the following picture.
  3. This server is probably pointing to the hybrid folder. But I didn't make research on that. The important thing is, that server is always synchrone with your source code.
  4. Next your app is being deployed to the Virtual Device. Again, you don't have to trigger any separate command to make this happen. All this is being done by using the "grunt serve" command.
  5. Here comes the interesting part.Your Virtual Android Device is always listening to http://10.0.2.2/8000 for changes. 





Known Issues

Failed to establish connection to ADB server

When starting the Google Android Virtual Device you get this error in the log.

Solution
  1. Go to AVD Manager
  2. Edit your AVD
  3. Uncheck 'Use Host GPU'option.
  4. Click Finish (Save).
  5. Then Start AVD again


ERR_EMPTY_RESPONSE

In my case, my local Google Cloud Endpoint server's Debug Port has been listening on port 8000. Check on your computer, if there are any other actions going on on this port.

Conclusion

It took me quite some hair to find out why this is working the way it is. Why is 10.0.2.2 pointing directly to the localhost of my development environmen although I never setup my development environment or anything else to make 10.0.2.2 my localhost.

The reason why this is working is because Google did setup their Android Virtual Device in a way, that 10.0.2.2 is always forwarding the request to the localhost of your development environment.

Here comes the big problem with this. If you want to use your own Android device or some other Virtual Machine, than this is not working, because they don't forward 10.0.2.2 to your localhost development environment. Genymotion, which is another famous Android Virtual Device software is using 10.0.3.2 as IP to forward to your localhost development environment. And if you would want to make this work from your real device, than you would have to take the IP of your development environment and point to that from device, instead of pointing to 10.0.2.2.

I did make some research and found out, that currently the 10.0.2.2 can't be changed and is a hardcoded value. This means, that currently you can only use the debug and liveReload functionality with the original Google Android Virtual Devices