{"id":3870,"date":"2018-02-16T13:54:55","date_gmt":"2018-02-16T13:54:55","guid":{"rendered":"http:\/\/www.nikola-breznjak.com\/blog\/?p=3870"},"modified":"2018-02-16T13:57:27","modified_gmt":"2018-02-16T13:57:27","slug":"create-android-cordova-plugin-showing-toast-popups","status":"publish","type":"post","link":"https:\/\/nikola-breznjak.com\/blog\/javascript\/create-android-cordova-plugin-showing-toast-popups\/","title":{"rendered":"How to create an Android Cordova plugin for showing Toast popups"},"content":{"rendered":"<h2>TL;DR<\/h2>\n<p>In this post, I&#8217;m going to show you step by step how to build a Cordova plugin for Android that shows a native Toast popup.<\/p>\n<p>You can check out the source code of the plugin <a href=\"https:\/\/github.com\/Hitman666\/cordova-android-toast\">here<\/a> and the source of the demo Ionic app that&#8217;s using this plugin <a href=\"https:\/\/github.com\/Hitman666\/IonicAndroidToastTest\">here<\/a>.<\/p>\n<blockquote><p>\n  In case you&#8217;re looking for the guide on how to write the Cordova plugin for the iOS platform, I wrote about it <a href=\"http:\/\/www.nikola-breznjak.com\/blog\/javascript\/ionic\/cordova-plugin-voip-push-notifications\/\">here<\/a>.\n<\/p><\/blockquote>\n<h2>plugin.xml<\/h2>\n<p>We start the process of plugin building by creating the <code>plugin.xml<\/code> file:<\/p>\n<pre><code>&lt;?xml version='1.0' encoding='utf-8'?&gt;\n&lt;plugin id=\"cordova-android-toast\" version=\"1.0.0\" xmlns=\"http:\/\/apache.org\/cordova\/ns\/plugins\/1.0\" xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"&gt;\n    &lt;name&gt;AndroidToast&lt;\/name&gt;\n\n    &lt;description&gt;Android Toast Plugin&lt;\/description&gt;\n    &lt;license&gt;Apache 2.0&lt;\/license&gt;\n    &lt;keywords&gt;android, toast&lt;\/keywords&gt;\n\n    &lt;engines&gt;\n      &lt;engine name=\"cordova\" version=\"&gt;=3.0.0\" \/&gt;\n    &lt;\/engines&gt;\n\n    &lt;js-module name=\"AndroidToast\" src=\"www\/AndroidToast.js\"&gt;\n        &lt;clobbers target=\"AndroidToast\" \/&gt;\n    &lt;\/js-module&gt;\n\n    &lt;platform name=\"android\"&gt;\n        &lt;config-file target=\"config.xml\" parent=\"\/*\"&gt;\n            &lt;feature name=\"AndroidToast\"&gt;\n                &lt;param name=\"android-package\" value=\"com.nikolabreznjak.AndroidToast\" \/&gt;\n            &lt;\/feature&gt;\n        &lt;\/config-file&gt;\n\n        &lt;source-file src=\"src\/android\/AndroidToast.java\" target-dir=\"src\/com\/nikola-breznjak\/android-toast\" \/&gt;\n    &lt;\/platform&gt;\n&lt;\/plugin&gt;\n<\/code><\/pre>\n<p>In this file you basically define:<\/p>\n<ul>\n<li>the platform this plugin supports (<code>&lt;platform name=\"android\"&gt;<\/code>)<\/li>\n<li>where the source files of your plugin will be (<code>source-file<\/code> elements)<\/li>\n<li>where is the JavaScript file that will be the bridge from Cordova to native code (<code>js-module<\/code> tag <code>src<\/code> property)<\/li>\n<li>what will be the plugin&#8217;s name by which you&#8217;ll reference it in the Cordova\/Ionic code (<code>&lt;clobbers target=\"AndroidToast\" \/&gt;<\/code>)<\/li>\n<\/ul>\n<h2>www\/AndroidToast.js<\/h2>\n<p>Next comes the so-called &#8216;bridge&#8217; file that connects the native and JavaScript side. It is common to put this file in the <code>www<\/code> folder. The contents of this file is as follows:<\/p>\n<pre><code>var exec = cordova.require('cordova\/exec');\n\nvar AndroidToast = function() {\n    console.log('AndroidToast instanced');\n};\n\nAndroidToast.prototype.show = function(msg, onSuccess, onError) {\n    var errorCallback = function(obj) {\n        onError(obj);\n    };\n\n    var successCallback = function(obj) {\n        onSuccess(obj);\n    };\n\n    exec(successCallback, errorCallback, 'AndroidToast', 'show', [msg]);\n};\n\nif (typeof module != 'undefined' &amp;&amp; module.exports) {\n    module.exports = AndroidToast;\n}\n<\/code><\/pre>\n<p>We created the <code>AndroidToast<\/code> function, which in other programming languages would basically be a class, because we added the <code>show<\/code> function on its prototype. The <code>show<\/code> function, via Cordova&#8217;s <code>exec<\/code> function, registers the <code>success<\/code> and <code>error<\/code> callbacks for the <code>AndroidToast<\/code> class and the <code>show<\/code> method on the native side that we&#8217;ll show now shortly. Also, we pass in the <code>msg<\/code> variable as an array to the native <code>show<\/code> function.<\/p>\n<h2>src\/android\/AndroidToast.java<\/h2>\n<p>The &#8216;native&#8217; code is written in <a href=\"https:\/\/www.ibm.com\/developerworks\/java\/tutorials\/j-introtojava1\/\">Java<\/a>:<\/p>\n<pre><code>package com.nikolabreznjak;\n\nimport org.apache.cordova.CordovaPlugin;\nimport org.apache.cordova.CallbackContext;\nimport org.json.JSONArray;\nimport org.json.JSONObject;\nimport org.json.JSONException;\nimport android.content.Context;\nimport android.widget.Toast;\n\npublic class AndroidToast extends CordovaPlugin {\n    @Override\n    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {\n        if (\"show\".equals(action)) {\n            show(args.getString(0), callbackContext);\n            return true;\n        }\n\n        return false;\n    }\n\n    private void show(String msg, CallbackContext callbackContext) {\n        if (msg == null || msg.length() == 0) {\n            callbackContext.error(\"Empty message!\");\n        } else {\n            Toast.makeText(webView.getContext(), msg, Toast.LENGTH_LONG).show();\n            callbackContext.success(msg);\n        }\n    }\n}\n<\/code><\/pre>\n<p>In the implementation file, we define our functions. We only have the <code>show<\/code> and <code>execute<\/code> functions in our example. When writing Cordova plugins for Android, every function from the bridge file has to call the <code>exec<\/code> function, which then calls the <code>execute<\/code> function on the native side. Then, based on the <code>action<\/code> parameter, we decide which function needs to be called. In our case, if we determine that the <code>show<\/code> action was called, we pass through the arguments to the private <code>show<\/code> function, which then uses the native <code>Toast.makeText<\/code> function to display the Toast message.<\/p>\n<p>When displaying the Toast, our <code>show<\/code> method needs access to the app&#8217;s global <code>Context<\/code>, which can be obtained using the <code>webView<\/code> object that we get from extending <code>CordovaPlugin<\/code>. This represents the running Cordova app, and we can get the global Context from there using: <code>webView.getContext()<\/code>. Other parameters to the <code>makeText<\/code> function define the text that we want to show and the duration of how long we want to show it.<\/p>\n<p>At this point you could customize the toast as much as the native Toast component allows, there are no restrictions even though this is used via Cordova as a kind of a &#8216;wrapper&#8217;. Some additional stuff that you could do is listed in the <a href=\"https:\/\/developer.android.com\/guide\/topics\/ui\/notifiers\/toasts.html\">official documentation<\/a>.<\/p>\n<h2>package.json<\/h2>\n<p>In earlier versions of Cordova, this file wasn&#8217;t required. You can generate it automatically with the help of the <code>plugman<\/code> package (install it with <code>npm install plugman -g<\/code> in case you don&#8217;t have it):<\/p>\n<p><code>plugman createpackagejson \/path\/to\/your\/plugin<\/code>.<\/p>\n<p>If you&#8217;re in the plugin folder, then the command is: <code>plugman createpackagejson .<\/code>. The <code>package.json<\/code> file in my case now looks like this:<\/p>\n<pre><code>{\n    \"name\": \"cordova-android-toast\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Android Toast Plugin\",\n    \"cordova\": {\n        \"id\": \"cordova-android-toast\",\n        \"platforms\": [\n            \"android\"\n        ]\n    },\n    \"keywords\": [\n        \"android\",\n        \"toast\",\n        \"ecosystem:cordova\",\n        \"cordova-android\"\n    ],\n    \"engines\": [{\n        \"name\": \"cordova\",\n        \"version\": \"&gt;=3.0.0\"\n    }],\n    \"author\": \"Nikola Bre\u017enjak&lt;nikola.breznjak@gmail.com&gt; (http:\/\/www.nikola-breznjak.com\/blog)\",\n    \"license\": \"Apache 2.0\"\n}\n<\/code><\/pre>\n<h2>Using the plugin<\/h2>\n<p>First, you need to install it. If you&#8217;re using Ionic:<\/p>\n<p><code>ionic cordova plugin add cordova-android-toast<\/code><\/p>\n<p>If you&#8217;re using Cordova:<\/p>\n<p><code>cordova plugin add cordova-android-toast<\/code><\/p>\n<p>In the code, you would show the toast message like this:<\/p>\n<pre><code>constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {\n        platform.ready().then(() =&gt; {\n            var androidToast = new AndroidToast();\n            androidToast.show(\n                'This is some nice toast popup!',\n                function(msg) {\n                    console.log(msg);\n                },\n                function(err) {\n                    console.log(err);\n                }\n            );\n\n        });\n    }\n<\/code><\/pre>\n<p>If you&#8217;re using the newest (currently 3) version of Ionic, then you would have to add this line: <code>declare var AndroidToast: any;<\/code> after the imports in <code>app.component.ts<\/code> (or any other file where you&#8217;ll use the plugin) before actually using it. If you&#8217;re using Ionic 1, you don&#8217;t need to do this.<\/p>\n<p>As a final note, make sure you&#8217;re accessing the plugin after the <code>platform.ready()<\/code> fires, just so you make sure that the plugin is ready for use.<\/p>\n<h2>Running the demo locally<\/h2>\n<p>Clone this repo:<\/p>\n<p><code>git clone https:\/\/github.com\/Hitman666\/cordova-android-toast.git<\/code><\/p>\n<p>CD into the cloned project<\/p>\n<p><code>cd cordova-android-toast<\/code><\/p>\n<p>Install the dependencies:<\/p>\n<p><code>npm install &amp;&amp; bower install<\/code><\/p>\n<p>Add the Android platform (please note that this process may take a while to complete):<\/p>\n<p><code>ionic cordova platform add android<\/code><\/p>\n<p>Add the plugin:<\/p>\n<p><code>ionic cordova plugin add cordova-android-toast<\/code><\/p>\n<p>Run the project on the device (if you have it connected):<\/p>\n<p><code>ionic cordova run android<\/code><\/p>\n<p>Run the project on the emulator:<\/p>\n<p><code>ionic cordova emulate android<\/code><\/p>\n<p>You should see something like this once the app runs on your device:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/nbz8NwD.png\" alt=\"\" \/><\/p>\n<h2>Conclusion<\/h2>\n<p>I hope this post gave you enough information so that you&#8217;ll be dangerous enough to go and fiddle with the Android Cordova plugin building yourself ?<\/p>\n<p>If you have any questions, feel free to reach out.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR In this post, I&#8217;m going to show you step by step how to build a Cordova plugin for Android that shows a native Toast popup. You can&hellip;<\/p>\n","protected":false},"author":1,"featured_media":3871,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[56,27],"tags":[],"class_list":["post-3870","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ionic3","category-javascript"],"_links":{"self":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/3870","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/comments?post=3870"}],"version-history":[{"count":3,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/3870\/revisions"}],"predecessor-version":[{"id":3874,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/3870\/revisions\/3874"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media\/3871"}],"wp:attachment":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media?parent=3870"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/categories?post=3870"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/tags?post=3870"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}