Showing posts with label Android Development. Show all posts
Showing posts with label Android Development. Show all posts

Tuesday, August 12, 2014

Javascript window.external.notify to communicate to WebBrowser control

How to communicate from web page loaded inside browser control to the hosting application

There are so many scenarios, where we may need to show web page inside our native applications such as Windows forms, WPF, Windows Phone, Android, iPhone etc... One of the scenario is to integrate with external authentication providers.

If we look at any third party authentication providers such as Google, Facebook, Azure ACS they don't let us take the user authentication details via our forms and get it authenticated using their web services. Instead the are strict in accepting the user name and password only through their web pages. The reason is security. If each and every application starts accepting user's Facebook or Google user name and password, there are chances that some of those apps will store the credentials locally and it might be miss used. That is the issue which is addressed by only allowing web page login even if we are in native applications.

The solution is, if we are developing even WPF or native mobile application and want to get external authentication we need to show their web page in our application. And once the authentication happens inside the browser, the native application can receive the security token and use it for subsequent operations.

For showing identity provider login page, we need to rely on the browser control available in the corresponding platform. If its WPF the browser control name is WebBrowser, in Android its named as WebView and in iOS its UIWebView. It is simple. First part is over, now our native application need to know when the authentication is completed, so that it can remove the browser control and obtain the token. This is the main topic of this post. In other words, the authentication happened inside the browser and browser need to to notify that event to the host application via some techniques.

The same technique, we can reuse the same technique if we want to notify any event happens inside the web page loaded inside the browser control.

Communication from HTML5 web page to WPF

WPF Browser control class has a property called ObjectForScripting. Assign any object to this property and it will be available as the window.external object in Javascript. So whatever methods are available in the class of the object assigned, those can be invoked from Javascript. For example, we created a class called HTMLInteropClass and that class has a method named MyMethod(). If we assign an object of that class to the WebBrowser.ObjectForScirpting property, we can invoke the MyMethod() written in C# from javascript using window.external.MyMethod() statement. Obviously the javascript should be downloaded from server or injected during run time to be running inside the browser control. Steps are as follows.

  1. Develop the interop class. Have the method inside it, which we are intended to call from javascript.
  2. Create object of that class and assign to the ObjectForScripting property of the WPF WebBrowser control.
  3. Point web browser control to the web page which is having invocation code. ie window.external.<methodname>()
  4. Develop the web page which is having the invocation code
More details here.

Communication from HTML5 web page to Android

In Android the web browser control name changes. But the handling is kind of same as of WPF browser control. Steps given below
  1. Develop a class in Java for Android application with method which will be called from javascript.
  2. In the onCreate() method of activity capture the webView reference and relate the object of above class with javascript using addJavascrtiptInterface() method.
  3. Make sure the Javascript is changed to call the method, present in the class created in step 1.
  4. Point the WebView to the page which contains the code to invoke our Android method.
More details here.

Communication from HTML5 web page to Windows phone

Windows phone uses a different way than WPF. It uses event based method invocation. ie We need to listen to the ScriptNotify event of WebBrowser. Steps below
  1. Subscribe to the ScriptNotify event.
  2. In the event handler e.Value gives the value sent from javascript
  3. The javascript code can invoke this method using window.external.notify("value");
This can be used in Silverlight as is. More details here.

Communication from HTML5 web page to iPhone

Here again the way is different. We cannot handle the window.external object directly. Need to follow a workaround. Whenever we want to communicate to the iOS UIWebView, we need to navigate to a dummy url and catch the navigation event in objective C code. We can use the webViewDidFinishLoad handler of UIWebView to capture the event. Steps below.

  1. Write code in JS to redirect the window.external invocations to a dummy url with data in its query string.
  2. Handle the webViewDidFinishLoad of UIWebView control and write the code in it.

More details here.

Tuesday, July 29, 2014

Android - Making Facebook login works in HTML5 app hosted inside WebView

Context - Develop one app for all machines / platforms.

The software stake holders always want to target a large audience regardless of what machine / plat form their clients uses. That is one of the reason why software are often written as web application. If we write as web application, at least in theory it can run in any machine whether it is laptop,tablet or mobile also regardless of the OS Windows / Linux / Mac used in those machines. Another advantage going with web is the less development cost as we are developing one application. Its the trend among the developers / organizations.

There are so many arguments going on whether we should go with this HTML5 web apps to address this problem in case we are targeting mobile platforms only. Some people argue that we should go with Xamarin kind of converging platforms. But that won't help to run the app in laptops.

Another requirement from the stakeholder will be to have native web app even if we have working web application. That is to make sure the application is present in the app stores in the way standard mobile applications are present and users don't need to worry about the web application url. They just need to install the mobile app from the store.

So only one way to meet the above requirement of running in desktops, laptops and as native mobile app is to develop application using HTML5 and create native wrapper applications which uses WebBrowerControl / WebView to show the HTML5 web site inside the native mobile app.

But will that make our the development life easier? If the application is very simple, it is easy. But when the application gets more features, problems will starting popping up. Below is one of the problem we faced in such a scenario.

Problem

The application needs to have Facebook login. It is easy to setup that using the Facebook javascript sdk. It worked well when we try this from laptop and the mobile browser. But when the same is tried from native Android wrapper we got an issue. After Facebook login, it ends up in a blank white page. 

The analysis leads to Android WebView limitations. The Facebook login SDK normally creates browser window child window and after login it will close that window and control will be passed to parent window. But when we show the same page using Android WebView control. That javascript popup window closing is not working.

Solution

The solution is as follows 
  1. Show the FB login popup in a different WebView control
  2. After the login success, close that window. 
How do we achieve that? Below are the tasks to be done.

Task 1 - Show login popup in different WebView

There is already a WebView in the application. We need to catch the javascript popup show event happened inside the web page and show that popup in a different WebView control. To do that we need to follow steps below
  1. Subclass WebChromeClient and override it's onCreateWindow method. Name it as UriWebChromeClient
  2. From the onCreateWindow method create object of new WebView control and add to the view.
    1. When we create the second WebView control, associate that to our custom WebViewClient which we are going to create in Task 2. That is required to close this second WebView.
  3. The new UriWebChromeClient class object needs to be connected to the existing WebView by calling webViewObj.setWebChromeClient() Method

Task 2 - How to know FB authentication is success to hide WebView

Now we need to think how the Android web view knows whether the FB login is successful. It can only be determined by looking at a particular URL(https://m.facebook.com/v2.0/dialog/oauth) where the FB will be redirecting after login success. How do the Android web view knows that the web redirection happens? It can be done by sub classing WebViewClient class. Steps below
  1. Subclass the WebViewClient class.Name it as UriWebViewClient
  2. Override the onPageFinished() method of WebViewClient in the new inherited UriWebViewClient class and check for the url. If the URL is "https://m.facebook.com/v2.0/dialog/oauth", we can decide that the FB authentication is completed and its time to hide the second WebView.
  3. Override the shouldOverrideUrlLoading() method too and do the similar.
The code is mentioned in this SO link .Only difference from this link is the onPageFinished method overriding.

Reference links

Monday, March 10, 2014

Not able to start Android application after adding activity through new Wizard in Eclipse

I normally add new Android activities, corresponding classes and config changes manually. Recently I came to visit a link from Kerala start-up village blog where they were explaining how to create new activity in Android. They mentioned in the same way I am doing. Or probably most of the developers are doing. Then I thought of other easy ways using Eclipse IDE or the Android plug-in to generate activity xml, its class and changes in the AndroidManifest and could see Android help page which explains the same. 

Just thought of trying it out by creating an activity into one of my Android project. After creating the activity, I was not able to run the application in simulator. The error got in the Console window is given below .

[time - app name] Installation error: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED
[time - app name] Please check logcat output for more details.
[time - app name] Launch canceled!

It suggests to check the logcat as well. So opened the logcat window and log reads as follows.

<time>: W/ActivityManager(407): No content provider found for permission revoke: file:///data/local/tmp/<name>.apk
<time>: I/PackageManager(407): Copying native libraries to /data/app-lib/vmdl-1401938519
<time>: W/PackageParser(407): /data/app/vmdl-1401938519.tmp (at Binary XML file line #12): <activity> does not have valid android:name

Here the console logs says that the manifest is malformed. In logcat window we could see 2 issues. One error says permission issue. And second line says activity does not have valid android:name property value. It means the activity which I added via the android wizard might have added incorrect entry to the android manifest xml file.

I started by googling the error message. Most of the SO links says its permission issue and I have to give full permission to C:\Users\<user name>\.android folder. I checked and could see it has full permission. Then I compared my faulty project's androidmanifest.xml file with other project and could see that the Android wizard which used to add activity has added the package name to the android:name. Earlier the name was .activityname. The wizard updated the activity name as packagename.activityname which caused the problem. Since the package name is already mentioned in the manifest root node, activity name cannot have the package name.

A sample has been given below

Wrong xml
<activity
            android:name="JoymonOnline.Malayalam.SwipeHost"
            android:label="@string/title_activity_swipe_host" >
</activity>

Corrected the android:name

<activity
            android:name=".SwipeHost"
            android:label="@string/title_activity_swipe_host" >
</activity>

Happy coding. 

Monday, February 24, 2014

My Android SDK and ADT Upgrade Experience

My last experiments with Android development was when I bought my first Android smart phone. Don't confuse by the word first smart phone, still I am using the same Galaxy Y. The truth is that after those days, I didn't get much time to play around due to various reasons such as busy with other technology stuff such as Big Data, Hadoop and project releases in Office. But recently I got a chance to do some research activities in Android phone. So started Eclipse again.

The research requires reading the calendar to get meeting details. The initial code base was set-up by one of my colleague and I am supposed to start from a zip file which he sent to me.He actually got the Zip from another one who left the company. The first challenge was how to check in the code into a repository. As our company mainly focus on the Microsoft technologies, we are using TFS. So downloaded and installed the TFS plugin for Eclipse. Things worked straight there. Then thought of compiling the project and here begins the story of upgrading Android development environment.


Since the calendar contact APIs are introduced in API Level 14, I had to have an environment which supports API Level 14. Mine was API Level 10 which is enough for developing apps for my Galaxy Y which uses 2.3.3 GingerBread. Things seemed straight as its the matter of upgrading the API levels. Opened the Android SDK manager but I was not able to find the API Level 14 to install. The installation starts from here.

Installing ADT

As all the developers know ADT is the Eclipse plug in for Android development. It provides the development support. My current ADT version doesn't support the API Level 14. So I started to install ADT 22.3.0. The first error started from here.The error was as follows

"A folder failed to be renamed or moved. On Windows this typically means that a program Is using that Folder (for example Windows Explorer or your anti-virus software.) Please momentarily deactivate your anti-virus software. Please also close any running programs that may be accessing the directory '..\android-sdk-dir\android-sdk_r12-windows\android-sdk-windows\tools'. When ready, press YES to try again."

If we look at the logs we can easily understand that the installer is trying to rename the tools folder to temp\ToolPackage.old01.Below is the log.

"Failed to rename directory ..\android-sdk-windows\tools to ..\android-sdk-windows\temp\ToolPackage.old01.

Done. Nothing was installed."

The google gave a bunch of ideas such as disabling antivirus which I never can do in my company machine, giving permissions,  renaming or moving some folders, killing some particular processes etc...Somebody even went to the extend of editing the install file. I did almost all the things except editing the install file. Since these methods are not helping, decided to setup the ADT from beginning.

It was smooth. I downloaded the SDK and extracted to new folder.Then changed the SDK path in the Eclipse and was able to install ADT and required API Levels. But when I run the application it got ended by the below message in the console window.

Upgrading All Android development supporting tools.

"Connection with adb was interrupted. 0 attempts have been made to reconnect. You may want to manually restart adb from the Devices view."

This tells more like a restart request. I tried restarting the simulator and Eclipse 2-3 times without any luck. Most of the links were talking about this issue in a USB debugging scenario. Since I am not using the USB debugging these things felt not applicable to me. Then thought of restarting the machine. But before restarting the machine decided to google once again with 'upgrade ADT' keyword in search. It gave one more SO link where says to upgrade everything when we upgrade ADT. I followed the same way and it got fixed.

Another error I got during this exercise was
"An internal error occurred during: "Launching com.myproject".
com.android.ddmlib.IDevice.installRemotePackage(Ljava/lange/String;Z[Ljava/lang/String;)Ljava/lang/String;

This also resolved when I installed everything fresh. The Eclipse tools which I upgraded are
Traceview, Hierarchy viewer, Android Development ToolKit & Dalvik Debug Monitor Service( DDMS)

Then I successfully executed the project which my colleague gave me and checked the source into TFS.

Changing the target in project.properties file

Then I thought of running my previous Android projects as those were my first study apps. But unfortunately they failed with below exception

[DateTime - Dex Loader] Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.
[DateTime - Test] Conversion to Dalvik format failed: Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.

Again googled. This time I was able to study about one more file called project properties. Since I have changed the build tools, I need to update this file to point to version 19. I changed the target from android-10 to android-19 and every project started working.

This might be familiar to the regular Android developers. But for developers like me who works mainly in other technologies, its a task.

Monday, May 7, 2012

Android designer - Online & offline

Came to an online designer for Android applications. They have the standalone version as well. Noway we can compare this as VisualStudio & Expression Blend partnership for WPF and Silverlight apps.

Seems Eclipse is better than this designer sometimes.
http://www.droiddraw.org/

Monday, April 30, 2012

Use actual Android phone instead of Emulator

Every time when I had entered into mobile application development the biggest challenge was how to transfer the application from the emulator development environment to the actual mobile phone. In Windows Phone 7 too moving developed app to phone is little difficult as we need a developer unlocked phone or developer account. But I think it is far more easier than moving an iPhone application from development environment to actual iPhone for testing purpose.

But in Android things are very easy .Just follow the below steps

  • Connect your phone via USB
  • Make sure the USB Debugging is enabled in Settings -> Application Settings -> Development
  • Start the application from Eclipse. It will ask you which device to use. Select your phone.

That's it .Your first Android application is in your Android phone. Even if you disconnect the USB the app will be present in phone. I have my first HelloWorld application in my Samsung Galaxy Y even till now.

My environment is Win 7 32 bit and has the software in the phone CD installed. It worked without any issue. Heard that there may be some issues with drivers and all. So check the below detailed link, if you face any issue in debugging in Phone.
http://developer.android.com/guide/developing/device.html

Monday, April 23, 2012

Select top N rows in Android SQLite

I had heard a lot about SQLite which is embeddable and small makes it suitable for mobile devices. But never got a chance to work on SQLite until I started Android. Setting up the data base and tables are little lengthy .So may be blog about those details later. This post is to note down a difference in using normal SQL and SQLite to fetch the top n rows.
The scenario was simple. We are showing some notifications in the app which are periodically syncing with the database using WCF services. The Android app uses SQLite to store the notification locally so that users will never miss any notification. It requests the latest notifications by sending the id of last notification it has. Its simple to fetch the highest id of notification rows using the normal SQL .The normal SQL query will look as follows
--Don't look at the * in query.Its sample
Select Top 1 * 
From Notifications
Order By Id
Desc

But the top is not supported in SQLite. We need to use the other keyword limit. It just limits the number of rows fetched

public Cursor select(String condition,String orderBy,String limit,SQLiteDatabase db){
    String qry=String.format("select * from %s order by %s desc limit %s", TABLE_NAME,orderBy,limit);
    return db.rawQuery(qry,null);
}

Interested in SQLite ? There are some more limits to SQLite.For more details refer the below.
http://www.sqlite.org/limits.html

Monday, April 16, 2012

Android : Mime type of .APK and hosting in GoDaddy

Recently we (a group of developers in my current company) developed a small Android app which gives real time updates of a Cricket tournament currently going on in the company .I am not a big fan of cricket even I am not participating in the tournament. But to utilize a chance to learn Android and develop a seasoned app I jumped into this :-) .We were little new to Android deployment scenarios and after developing the first version we came to face the big problem in deployment. We need to get an account in google play market which has some fees in dollars !!! . For a developer in US who draws pay checks in dollar this may not matter .But as we are getting salary in INR, a small confusion started. Company is ready to pay but it may take some time .So decided to host in my personal hosting space which is purchased from godaddy.com .

Things were easy in terms of copying the apk vie FTP. But when we tested from Android mobile it showed an error. Not able to recognize the file because there is no mime type defined for .APK files in the server. It took 30mins in Godaddy interface to realize they don't have support for adding mine type. But soon we remembered the advantage of IIS 7.0 .It allows us to add mime type via the web config.

The mime type of Android application file extension ".APK "is "application/vnd.android.package-archive" .So it was a simpe task of adding the below config entry into the System.WebServer section.

  <system.webServer>
    <staticContent>
      <remove fileExtension=".apk" />
      <mimeMap fileExtension=".apk"
               mimeType="application/vnd.android.package-archive" />
    </staticContent>
     <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

Yes.Now the app is ready from my hosting space.The mobile almost deals the app like how we install from the market. Do we really need the google play market ?Its true that it has a broad reach.

Tuesday, April 3, 2012

What is LogCat in Android and how can I see logs?

As normal, immediately after starting Android development, I begun editing files directly and in the same speed, I got an error which refer to something called logcat? Error shown was as follows in the console window.


[2012-03-03 12:04:00 - HelloAndroid] Installing HelloAndroid.apk...
[2012-03-03 12:04:01 - HelloAndroid] Installation error: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED
[2012-03-03 12:04:01 - HelloAndroid] Please check logcat output for more details.
[2012-03-03 12:04:01 - HelloAndroid] Launch canceled!
[2012-03-03 12:05:26 - HelloAndroid] ------------------------------

This says something happened while deploying the app to the emulator / device .But for details I need to check something called logcat ? Where is that LogCat located ?

It is another window related to Android development in Eclipse .You can show that as follows.

Widnow -> Show View -> LogCat (with the Android logo)

If you are not able to locate in the show view sub menu select

Window -> Show View -> Others -> Android -> LogCat

This windows is just an UI to see the logs. You can even read and write to the logs. It is little difficult to understand the LogCat messages at first. But will be familiar with no time. My issue was I edited the name of an activity which was mentioned as the Launcher in AndroidManifest.xml. So make sure while renaming the activity modify your manifest as well.

Saturday, March 24, 2012

Opening copied Android project in Eclipse

If you are working with the Eclipse tool for years, you will laugh at this .But this is for the developers like me who came to Eclipse from Visual Studio. In VSTS its very easy we have a .sln file and that cane be directly opened even if we port the project to a new machine or we got a new machine.

The things were not easy for me when I got new Win 7 machine. I backed up every project which were there in my vista machine. Then I setup the Android environment in new machine.Setting up is another big story. There are so many links 1 out there to setup the Android environment. After that when I tried to open my old project I was not able to find any option to open project through menu. ie it lacks File-> Open -> Project or File -> Open Project .Even I was not able to find what is the project file in the folder which I have. There are files with only extension such as .classpath and .project etc...I tried opening that but no chance.

While creating new project there is an option called "Create project from existing source" ie File -> New -> Android Project. I tried that but it said

"An Eclipse project already exists in this directory. Consider using File > Import > Existing Project instead"

Got another clue .I need to import old project. Then I tried that way .It first needed a workspace and when I created a workspace things started working.Thanks God...

Now I really understood why most of the Java training courses include more sessions on "How to use Eclipse?" where .Net teaches you about the language and framework without more importance to VS.

1 See the below links in order to setup environment.
http://developer.android.com/sdk/index.html
http://developer.android.com/resources/tutorials/hello-world.html
http://www.codeproject.com/Articles/102065/Android-A-beginner-s-guide