Interactive SVG image in Android app using Kotlin and JavaScript
In this software development era, applications are upgrading so fast as users always want to see any new technologies or features in their personal way. So that developers had to update themselves to fulfill user’s requirements and expectations in a very unique way. When its time for implementation as developers, sometimes we get help from different sources and sometimes we need to find our own way.
Well, here is my history of survival which I would like to share! (Don’t be afraid I won’t take long…)
As I was asked to build a feature for some reason and it was obvious to make that happen with SVG image file and that must be interactive as well. So, I started searching how to do that. Well, I found Macaw which exactly serves my purpose! But unfortunately it was for iOS platform only!
Unlikely the iOS library support for this, to be honest I didn’t able to find any library to implement this feature properly. And I don’t understand how to do it anyways. ImageView may able to hold the SVG image but that won’t be intractable, I had to find an alternative way.
After several hours of research I found out a hack to implement this, inspired from Ms. Elye’s story about Android interacting with Web App. I came to a decision to take a little risk, I will say it’s a pretty much success as well. I know questions are already started pop up into your mind one of them is “How?” Ok, Ok… I understand. I’m sharing the process, code and stuffs now. So, brace yourself… [N:B: I would recommend you to take a tour to her story before diving into mine].
How will a native app communicate with the SVG image?
Ans: Using JavaScript!
— Wait, what???!!!! Are you kidding me?
— Told you to read Elye’s story! Well, basically we will be using interfaces for both native and web applications. Please don’t panic, this sample github project of mine will provide all the answers. Just clone it and run it if you want to check how it works!
Okay no more fun! So, here is the checklist of processes we will be going to do: -
- Load an SVG file into a web application, by downloading the image from an url load it into WebView using raw HTML file loading technique.
- Setup the interaction controller (.js) according to the SVG body for interactive paths
- Setup a callback-bridges to communicate between native application and web application
Rendering an SVG image into web app
- Get the SVG image url, this will be sort of downloading file from the server and then parse the
xml
code in it. Here, as I’m using Retrofit and LiveData; but you can do your own. My way is like below:
3. Here comes the first little hack part webView.loadDataWithBaseURL
which helps to load custom HTML code into the WebView we have been using into the layout file. So, our goal is to load the SVG file into the host HTML and load it into the WebView. To do that, we need to put the SVG file (or it’s body) inside the HTML host body and then load the page and BOOM!
So, made a HTML skeleton to be the host of my parsed SVG file/body. Here is the skeleton :
4. You can see I am doing two special things while creating the HTML page.
i) Injecting the SVG body/xml inside the <div>
tag, which is why the SVG is get to load into the HTML host into our webView
.
ii) Including a JavaScript file using the named index.js
which is responsible for the interaction on SVG image loaded into the WebView. (wait for it)
Finally, we will call following line of code webView.loadDataWithBaseURL(BASE_URL,getHTMLBody(svgString),"text/html",“UTF-8”, null)
Here, BASE_URL is the directory where the external files (i.e: .js files) will be available, which is always file:///android_asset/<folder_name>/...
So, yeah! That’s pretty much all about downloading and previewing an svg image into our native application using web application.
Tap handling: Setup interaction controller with JavaScript
So, now we’ve came to the point of this project where we need to interact with the paths already included into the SVG code. We will fire a click event when user interacts with a path and do our own customization after receiving that and send data to native application using a delegate or the callback-bridges I’ve mentioned earlier (as needed). Before we start here is some rules I have to share that we must keep in mind.
Okay, let’s start... (N:B: I’m assuming you’re able to communicate between native and web app now.)
Here I am reading the total SVG code lied into the HTML div class and checking if there is any path id which I want to interact with. In this following case I am using “Code_” as the prefix of each id to find it. (ref: Check this rules here again). So, I traversed the document searching for the path ids which starts with “Code_” and get the exact list of paths I want to interact with; just like this:-
So, We got the list of the interactive paths from the SVG image file. Now, It’s time to handle the click or tap event when a path has been clicked or tapped from the SVG. To do so, we need to provide an addEventListener(…)
to doSomething() right? Okay then let’s see what we can do. Let’s check out the following code snippet below:
Well, as we can see from above there is an iteration through the tablePathList
and getting which path id got the interaction using event.target.id
and then getting it’s title from path’s body and updating (toggling) it’s current style with new one and vice versa. Now the last work to be done to our project is putting the .js file into the asset folder into our whole project.
Additional notes:
Don’t forget to cleanup
Upon exit as Ms. Elye suggested, we should remember to clean up the @JavascriptInterface
to avoid any further memory leaks. e.g.
override fun onDestroy() {
webView.removeJavascriptInterface(JAVASCRIPT_OBJ)
super.onDestroy()
}
And yeah, pretty much that’s all. Let’s see what we’ve done so far.
Hope you sailed through the how-to smoothly and managed to implement interactive SVG image using JavaScript merging with your native app. If you have any questions, just let me know!
I hope you appreciate this post and it’s helpful for you. Do share with others.
Cheers!!!
Checkout the full project on my github.
Thanks for reading!