Nikola Brežnjak blog - Tackling software development with a dose of humor
  • Home
  • Daily Thoughts
  • Ionic
  • Stack Overflow
  • Books
  • About me
Home
Daily Thoughts
Ionic
Stack Overflow
Books
About me
  • Home
  • Daily Thoughts
  • Ionic
  • Stack Overflow
  • Books
  • About me
Nikola Brežnjak blog - Tackling software development with a dose of humor
Go

How to dockerize a simple Go app

In this tutorial, I’m going to show you how to dockerize a simple app (written in Go) that shows the current time. Github repo is here, in case you’re interested.

Dockerfile

So, if you haven’t played with Docker before, official docs would be a good start.

For our Go app, we need to create a file named Dockerfile with the following content:

FROM golang:onbuild
EXPOSE 8080

Go code

As for our app, the code is rather short and simple:

package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
    curTime := time.Now().Format("02.01.2006 15:04:05")

    fmt.Fprintf(w, "%s", curTime)
}

If you haven’t played with Go before, official docs would be a good place to start.

The only important thing to note here is that we’re listening on port 8080, which we need to set in the Dockerfile through EXPOSE.

Steps on how to make this yourself

Go code

  • Create the Go app (for testing purposes, you may use the same exact code)
  • Test it locally with go run curtime.go
  • Open your browser and go to http://localhost:8080
  • You should see the current time displayed

Docker

  • Create a Dockerfile with that content (Make sure you set the correct port in case you’ll be using a different one)
  • Inside the source folder (where you have curtime.go and Dockerfile) run docker build -t yourUserName/curtime . – this will create the image
  • You can check if the image was created with docker images
  • Run the image in a container: docker run -d -p 8000:8080 yourUserName/curtime
  • Access the app via your browser on port 8000. I used 8000 and 8080 intentionally so that it’s easier to explain that the 8000 port is the one on your computer and the 8080 is the port to which we’re ‘binding’ to

Few other useful Docker commands:

  • docker ps will list all the running containers. By adding the -a switch, you’ll see even the stopped ones
  • docker stop – stop the running container
  • docker rm containerID – delete the container with id containerID
  • docker images – list the images that are on your machine
  • docker rmi imageID – delete the image with id imageID

How to #dockerize a simple #Go app? https://t.co/JSIrP3CHYO

— Nikola Brežnjak (@HitmanHR) January 18, 2017

Meetups

5th MeCoDe meetup in Čakovec – Laravel

This post comes sooo late, but better late then never they say 🙂

This was the first meetup since we changed our name from Ionic framework meetup. The sole reason for that was that we don’t want to convey the message that we’re talking only about Ionic. As you all know, and can see in the previous meetups, we’ve been covering a lot of ground in the web development and design world in general, and we plan on continuing with this practice.

Also, we have a new logo, thanks to our Goran Levačić – thank you!

Our 5th MeCoDe Meetup was held on 1st of December, 2016. It was titled Uvod u Laravel – najpopularniji PHP framework današnjice.

I would like to thank our Meetup member, Srđan Srđenović the CEO of Koder who was the presenter this time and who did a great job presenting the material and showing us why Laravel is the most popular PHP framework these days.

We learned about:

  • the MVC in Laravel
  • how to install it
  • how it’s structured
  • how to configure it
  • how to work with Artisan
  • how the eloquent model works
  • how to set up routes and views

and we did all that on our computers, which is always cool to have some working app when you go home from a meetup.

Few pics from the meetup:

[ngg_images source=”galleries” container_ids=”16″ override_thumbnail_settings=”0″ thumbnail_width=”120″ thumbnail_height=”90″ thumbnail_crop=”1″ images_per_page=”20″ number_of_columns=”0″ ajax_pagination=”0″ show_all_in_lightbox=”0″ use_imagebrowser_effect=”0″ show_slideshow_link=”1″ slideshow_link_text=”[Show as slideshow]” order_by=”sortorder” order_direction=”ASC” returns=”included” maximum_entity_count=”500″ display_type=”photocrati-nextgen_basic_thumbnails”]

I’ll take the opportunity to announce the 6th MeCoDe meetup: ‘Why Azure’ that will take place on 26th of January, 2017. You can read more details about the meetup on the MeCoDe Meetup page. See you there!

Pluralsight

Notes from Kanban Fundamentals course on Pluralsight

Here are my notes from the very good Pluralsight course Kanban fundamentals by Steve Smith.

  • Kanban = kan (visual) & ban (card)
  • Taiichi Ono from Toyota 1920ies
  • Kanban is about maximizing flow
  • It’s for visualizing work and limiting WIP (work in progress)
  • Little’s Law states that queue length (L) = arival rate * avg. wait time.
  • Cycle time = WIP / Throughput
Lead time vs Cycle time
Ticket created Start work Ticket implemented
Lead time
  Cycle time

Personal Kanban

  • Visualize work
  • Limit WIP

  • Book reference: Personal Kanban

Personal Kanban getting started

  • Gather materials (sticky notes, whiteboard, pens)
  • Establish Value stream (Ready/Doing/Done)
  • Make your backlog explicit (put them on sticky notes, focus on completeness, not organization)
  • Establish WIP limit
  • Begin pulling tasks
  • Reflect

Create a blocked state too – prioritize them and set a WIP on them as well!

Potentially, add a Today column:

  • Important and Urgent matrix by Dwight Eisenhower
  • Quadrant of Kaizen – important but not urgent.

Prioritization lanes:

Kanban for software teams

  • Book Reference: Kanban – Successful Evolutionary Change for Your Technology Business

Usually, the upstream process (UP) would produce as fast as they could without worrying about the downstream process (DP) – this lead to a lot of waste = overproduction.

However, in the pull model, the DP requests more parts, and the UP produces just enough items to keep the store populated with some limited number of parts.

The Kanban Method** Properties

  • Visualize workflow
  • Limit WIP
  • Measure and manage flow
  • Make process policies explicit
  • Use models to recognize improvement opportunities

Recipe for success

  • Focus on quality – reduces defects
  • Reduce WIP – reduces defects as well
  • Deliver often – as that builds trust
  • Balance demand against throughput – don’t accept work at a rate higher than the rate your team produces work. This will yield bottlenecks
  • Prioritize
  • Attack sources of variability to improve predictability –

Microsoft case study 2004:

  • remove estimations
  • limit WIP
  • More frequent cadence

Implementing Kanban

  • Define your process and endpoints
  • Identify types of the workflow
  • Create a card wall
  • Establish and visualize queues/buffers

Examples

Example usage for ‘swimlanes’ (horizontal lines denoting ‘critical’ tasks that eventually happen):

An example of post it notes on the actual physical board in case that’s used.

Online Tools

The author mentioned the following tools:

  • AgileZen
  • LeanKit
  • Trello
  • Targetprocess

However, this list is rather old. Even so much so that at the time Trello was free, and it just got sold yesterday 🙂

I’d like to add one kanban tool that I use for personal usage: https://kanbanflow.com. And one that I’m about to start using, and will write my thoughts about how well is fitting in our workflow after I do some work with it: https://www.blossom.co/.

Conclusion

Very good introduction to Kanban, which may be just as much as you’ll ever need.

My notes from Kanban Fundamentals course on Pluralsight https://t.co/tOQ0Nen0nY

— Nikola Brežnjak (@HitmanHR) January 11, 2017

Miscellaneou$

After writing 300 posts, this is why I think you should start blogging too

TL;DR

In this post I’m going to share with you:

  • few things that I learned from writing 300 posts
  • why I think you should start blogging as well
  • my thanks to one ever so slightly awesome role model

Backup your stuff

This tip may come as unexpected, given the fact that this is actually a 302nd post on my blog and one could argue that by now I have some system in place for dealing with that, right? Well, yeah, but so it is that this is the second time I’m writing this post from scratch.

Yeah, please don’t ask; I always keep a backup of backups (how meta, right?) but in this particular case, I was ‘smart’ and had it on my Desktop.

Seriously bro, Desktop!? What are you, like, 2015!?

I know, I know.

Don’t you, like, have Time Machine backup, or something.

Yeah, I do, but it wasn’t backed up… You know what, please just stop putting additional salt on the already burning wounds. Thank you very much, it’s enough of a lesson without it.

Actually, you know, just the other day I watched this movie, and it could be that my safest bet would probably be to ask (nicely, of course) No Such Agency if they have it on file somewhere. OK, joking a bit; I honestly don’t care – we may as well all be in The Truman Show and so what – do your best with the hand you’ve been dealt.

The beginnings

One doesn’t come to write 300 posts overnight, and we all start somewhere. My humble beginnings started on August 15, 2013, when I published my first post about Carcassonne scoring board application. I wrote the 100th post overview on December 28, 2014, and the 200th post overview on August 20, 2015.

With this 300th overview being published today on the last day of 2016, I’m roughly below 100 posts in average per year, which is not too shabby, but I’m striving to do better.

My approach

I’m happy to say that my approach hadn’t changed from the time when I wrote the 200th post overview and that it’s still some kind of an inner drive to:

…help people by bridging this seemingly invisible gap between the awesome programmers and not-so-awesome programmers who would use a bit of step by step help, by making my tutorials straight to the point with each step, without skipping the ever so slightly “obvious” parts.

OK, but why!?

OK, seriously now man, in this day and age, tell me what are you getting out of this?

Let me be lazy and use the same quote I did last time:

You learn the best when you have to teach someone something.

So, when I learn something new, or when I stumble upon a problem that I can’t solve for some time I benefit from documenting it on my blog in few ways:

  • I tend to remember things way longer when I actually write them down
  • I potentially help someone else who may stumble at the same error in future
  • I have a reference for when I need to look it up

Also, by breaking things down to the core concepts and then being able to see the bigger picture is an invaluable skill to have, and Einstein said it best:

If you can’t explain it simply, you don’t understand it well enough.

Seriously, where’s the catch!?

There’s not. And, in case you don’t buy into all this I just want to help you with my blog, you can take a look at the number of my StackOverflow answers, two books (1, 2) I’m giving away for free, or come to a free meetup that I’m hosting once a month. Anyways, I’m not trying to market myself or show how super I am; I’m merely making a point as to what I’m saying.

Opportunities and why I think you should start writing a blog

However, (aha!, now we have him!!), I have to tell you one thing that will inevitably happen. As you start writing a blog and solving things and publishing it for other people to learn from you will inevitably come out as an expert in the field (in case you specialized) and thus you’ll get more opportunities than you can even imagine. Book writing offers, consulting and conference speaking gigs, you name it.

The process of achieving consistency

I’m a firm believer in processes that are used and cultivated for good, as it takes a lot of “I don’t feel like it” situations out of an equation. And, I believe, you know that these days tend to just ‘happen’, and then magically stretch on for weeks until you gather your thoughts and snap out of it.

Thus, my advice for writing more is nothing new, and you hear it probably all over the Internetz. The problem is that its hard, and people tend to run away from hard things these days. The sole ‘tool’ which you have to nurture, train and maintain is consistency.

Put in the work daily, fail, learn, get up, improve, put in the work, fail, learn, improve. Mary go round… The next thing you know it, you won’t be thinking about the process anymore, you’ll live it, preach it. However, this is hard, I know. But you’re in it for the long run, remember? So, put your hand on the plow and keep on…

Thus, if you want to start writing blog posts about some topic, just start today. Don’t go and read a book on the topic (chances are you’ll never finish it in the first place :/). Just freaking do it already! Share what you’ve learned along the way. In case a year from now you won’t be ashamed by the quality of your posts you did back then, then my friend, you haven’t grown, and it’s time for some introspection (the same rule applies to your code if you’re a software developer).

Read more nonfiction books

Don’t get me wrong; one can learn from fiction books as well. However, imagine you read 10 pages a day of some book that’s related to what you’re trying to achieve (C#, PHP, Soft skills, Finance even, …).

No, Facebook doesn’t count. Drop that already. That’s like talking into the wind if you’re talking at all, that is.

In one month you would read 300 pages of some book. And in one year you’d read 12 books. Now, imagine you take and apply only one idea from each of those books – how different do you think your life would be? How much more valuable do you think you could be to your society, spouse, child, yourself if you invest in yourself?

Ok, and now to address the elephant in the room:

What is this new age success/growth mindset that you’ve got going on here?

Yeah, the only post where I kind of touched this was the one about Makers vs Consumers – don’t hate, donate. And, I’m not going to ramble on and on why you should read more. I’m just going to say that I agree with the following quote:

Your level of success will seldom exceed your level of personal development.
~ Jim Rohn

Homerun posts

Two posts that I’m very proud of (and have been published on Pluralsight) are:

  • Getting started with Angular 2 by building a Giphy search application
  • Ionic Framework: A definitive 10,000 word guide

Few of the posts on this blog have indeed been doing well:

  • Posting data from Ionic 2 app to a PHP server
  • How to run Node.js server in Ionic mobile app?
  • How to send an email in Ionic framework application?
  • Introduction to TDD in Ionic framework

Few other posts worth mentioning:

  • Makers vs Consumers – don’t hate, donate
  • Why am I getting Unexpected token ‘\u0000’ when using npm install -g package
  • How to set up live Markdown preview on Windows with Sublime Text and Markmon
  • Raneto Google OAuth login
  • How to create a native iOS app that can receive VoIP push notifications

What’s next for me?

I’ve been putting off blogging about Ionic 2 for far too long now, and now when the dust has settled, I’m going to go into this fully, so expect a flood of posts concerning that in this year. As I still work on Ionic 1 codebase, expect to get some ‘hard-learned tips’ for working with the framework from day 1.

On a totally different note, I started looking into the Go language and am liking it so far. I hope that my journey will evolve so that I’ll be able to work with it even more on a professional level as well. Be it as it may, expect some posts on that subject when I gain some more knowledge about it.

Special thanks

I’ve read a few books that could be classified as ‘self-help/self-improvement’ books, and (surprisingly so?) I’ve read a lot of the software development books. However, it was not until I read John Sonmez book Soft Skills (you can read my review here) that I started taking all this a bit more seriously and started reading way more about all of this.

I still remember when I emailed him asking if Ionic framework was a good technology to niche down. Now, a year and a half later, being in the top #3 answerer in Ionic framework tag on Stackoverflow I can only say – thank you.

In case you’re into improving as a software developer and getting to the next level of your personal development, be sure to check his Youtube channel. Who knows, you may just find something valuable for you.

Some of you may also be familiar with Elliott Hulse, and if so, you’ll enjoy their interview.

Conclusion

My intention was not to make this into a motivational speech. Though, if it helped kick you out of your comfort zone and into the producer mentality, that’s great. However, don’t forget:

Inspiration is for amateurs – the rest of us just show up and get to work.

So, wish you a happy, healthy, fulfilling and productive 2017!!

After writing 300 posts, this is why I think you should start blogging too https://t.co/RkFwPNZjib

— Nikola Brežnjak (@HitmanHR) December 31, 2016

Miscellaneou$

Ekobit DevArena 2016

TL;DR

In this post, I’ll show you some pictures and notes from the Ekobit DevArena 2016 conference.

Previous conferences

In case you’re interested here are the posts from the last two that I attended:

  • DevArena 2014
  • DevArena 2015

One does not simply skip breakfast…

Yeah, I eat too much, don’t invite me to your events unless you’ve got plenty to eat

¯\_(ツ)_/¯

This is how the accreditation looked on the back side, with the list of presentations per each track (4 in total):

I was super lazy this year regarding note taking, so I’ll pull a lazy on you and just show you the pictures that I took from each of the presentation that I attended.

They say that the picture is worth a thousand words. Well, in that case, this post is a lot of thousand words long 🙂

Keynote

[ngg_images source=”galleries” container_ids=”8″ override_thumbnail_settings=”0″ thumbnail_width=”120″ thumbnail_height=”90″ thumbnail_crop=”1″ images_per_page=”20″ number_of_columns=”0″ ajax_pagination=”0″ show_all_in_lightbox=”0″ use_imagebrowser_effect=”0″ show_slideshow_link=”1″ slideshow_link_text=”[Show as slideshow]” order_by=”sortorder” order_direction=”ASC” returns=”included” maximum_entity_count=”500″ display_type=”photocrati-nextgen_basic_thumbnails”]

Tesla 🙂

[ngg_images source=”galleries” container_ids=”9″ override_thumbnail_settings=”0″ thumbnail_width=”120″ thumbnail_height=”90″ thumbnail_crop=”1″ images_per_page=”20″ number_of_columns=”0″ ajax_pagination=”0″ show_all_in_lightbox=”0″ use_imagebrowser_effect=”0″ show_slideshow_link=”1″ slideshow_link_text=”[Show as slideshow]” order_by=”sortorder” order_direction=”ASC” returns=”included” maximum_entity_count=”500″ display_type=”photocrati-nextgen_basic_thumbnails”]

EU funds

[ngg_images source=”galleries” container_ids=”10″ override_thumbnail_settings=”0″ thumbnail_width=”120″ thumbnail_height=”90″ thumbnail_crop=”1″ images_per_page=”20″ number_of_columns=”0″ ajax_pagination=”0″ show_all_in_lightbox=”0″ use_imagebrowser_effect=”0″ show_slideshow_link=”1″ slideshow_link_text=”[Show as slideshow]” order_by=”sortorder” order_direction=”ASC” returns=”included” maximum_entity_count=”500″ display_type=”photocrati-nextgen_basic_thumbnails”]

Angular 2

[ngg_images source=”galleries” container_ids=”11″ override_thumbnail_settings=”0″ thumbnail_width=”120″ thumbnail_height=”90″ thumbnail_crop=”1″ images_per_page=”20″ number_of_columns=”0″ ajax_pagination=”0″ show_all_in_lightbox=”0″ use_imagebrowser_effect=”0″ show_slideshow_link=”1″ slideshow_link_text=”[Show as slideshow]” order_by=”sortorder” order_direction=”ASC” returns=”included” maximum_entity_count=”500″ display_type=”photocrati-nextgen_basic_thumbnails”]

Microservices

[ngg_images source=”galleries” container_ids=”12″ override_thumbnail_settings=”0″ thumbnail_width=”120″ thumbnail_height=”90″ thumbnail_crop=”1″ images_per_page=”20″ number_of_columns=”0″ ajax_pagination=”0″ show_all_in_lightbox=”0″ use_imagebrowser_effect=”0″ show_slideshow_link=”1″ slideshow_link_text=”[Show as slideshow]” order_by=”sortorder” order_direction=”ASC” returns=”included” maximum_entity_count=”500″ display_type=”photocrati-nextgen_basic_thumbnails”]

Electron

[ngg_images source=”galleries” container_ids=”13″ override_thumbnail_settings=”0″ thumbnail_width=”120″ thumbnail_height=”90″ thumbnail_crop=”1″ images_per_page=”20″ number_of_columns=”0″ ajax_pagination=”0″ show_all_in_lightbox=”0″ use_imagebrowser_effect=”0″ show_slideshow_link=”1″ slideshow_link_text=”[Show as slideshow]” order_by=”sortorder” order_direction=”ASC” returns=”included” maximum_entity_count=”500″ display_type=”photocrati-nextgen_basic_thumbnails”]

React

[ngg_images source=”galleries” container_ids=”15″ override_thumbnail_settings=”0″ thumbnail_width=”120″ thumbnail_height=”90″ thumbnail_crop=”1″ images_per_page=”20″ number_of_columns=”0″ ajax_pagination=”0″ show_all_in_lightbox=”0″ use_imagebrowser_effect=”0″ show_slideshow_link=”1″ slideshow_link_text=”[Show as slideshow]” order_by=”sortorder” order_direction=”ASC” returns=”included” maximum_entity_count=”500″ display_type=”photocrati-nextgen_basic_thumbnails”]

React Native

[ngg_images source=”galleries” container_ids=”14″ override_thumbnail_settings=”0″ thumbnail_width=”120″ thumbnail_height=”90″ thumbnail_crop=”1″ images_per_page=”20″ number_of_columns=”0″ ajax_pagination=”0″ show_all_in_lightbox=”0″ use_imagebrowser_effect=”0″ show_slideshow_link=”1″ slideshow_link_text=”[Show as slideshow]” order_by=”sortorder” order_direction=”ASC” returns=”included” maximum_entity_count=”500″ display_type=”photocrati-nextgen_basic_thumbnails”]

Prize draw

They had a nice additional prize draw for those who asked questions (you get a small paper which you toss in a drawing bowl). I got 4 of them this year. However, no luck in winning something again 🙁

Ekobit #DevArena 2016 https://t.co/czNvnGJpGr

— Nikola Brežnjak (@HitmanHR) October 27, 2016

Ionic

4th Ionic framework meetup in Čakovec

Our 4th Ionic Framework Meetup was held last Thursday, 13th of October. It was titled Designing with Macaw, and it was all about design this time.

I would like to thank Goran Levačić, the leader of incubation and education in TICM who was the presenter this time and who did a great job presenting the material and showing us some practical things in InVision and Macaw.

It will be interesting to see what the future brings since Macaw was acquired by InVision just recently and they announced that they would combine these two tools into one product till the end of 2016. This way both designers and developers will have a common platform through which they will be able to work more efficiently together.

Few pics from the meetup:

In case you’re interested in next events, be sure to check out the meetup page and join the discussion there.

Ionic

Cordova plugin for VoIP push notifications

TL;DR

This plugin didn’t exist, so I made it – Cordova plugin for receiving VoIP push notifications on iOS 8.0+ only.

Installation

For Ionic:

ionic plugin add cordova-ios-voip-push

For Cordova:

cordova plugin add cordova-ios-voip-push

Usage

var push = VoIPPushNotification.init();

push.on('registration', function(data) {
    log("[Ionic] registration callback called");
    log(data);

    //data.deviceToken;
    //do something with the device token (probably save it to your backend service)
});

push.on('notification', function(data) {
    log("[Ionic] notification callback called");
    log(data);

    // do something based on received data
});

push.on('error', function(e) {
    log(e);
});

Please see the Ionic demo for the exact usage example.

Running the demo

Ionic setup

Clone this repo:

git clone https://github.com/Hitman666/cordova-ios-voip-push.git

CD into the cloned project and the Ionic demo project:

cd cordova-ios-voip-push && cd ionicDemo

Install the dependencies:

npm install && bower install

Install the platform and plugins (please note that this process may take a while to complete):

ionic state reset

Add the plugin (either one of three options would work):

ionic plugin add cordova-ios-voip-push

or

ionic plugin add ../thePlugin/VoIPPushNotification

or like this:

ionic plugin add https://github.com/Hitman666/cordova-ios-voip-push.git

Prepare the project:

ionic prepare ios

Open the project in XCode by going into platforms/ios and opening up the pluginTest.xcodeproj file.

XCode setup

If you don’t have an AppID and VoIP push certificate created in your Apple developer account, you can do so by following my instructions from the How to create a native iOS app that can receive VoIP push notifications tutorial.

Take your time to do that an then come back, I’ll wait.

To use the VoIP push in the app, you need to turn ON the Background Modes for your app and check few of the checkboxes:

Make sure you select the following options:

  • Audio, Airplay, and Picture in Picture
  • Voice over IP
  • Background fetch
  • Remote notifications

Next, you need to add PushKit framework to your project:

Also (yeah, I know, a lot of setup), you need to make sure that you set the appropriate Bundle Identifier. You should have read about this in the tutorial I linked above.

After you run the project, in the XCode console you should see

and on your device:

You can send VoIP pushes to yourself by editing the simplepush.php file (in the pushSendingScript folder from the Github repo). Just make sure you add your own device id that you’ll see show up on your phone. You have more options to send VoIP push, two of which you can read in the post linked few times above.

!TL;DR

Disclaimer:
This tutorial was inspired by the official phonegap-plugin-push plugin, and the fact that this kind of VoIP support didn’t exist. There were requests for it here, here and here. As well as on freelance sites like here, here – hehe, hope these guys will send some donations to my favorite charity if they end up using this now 😉

Also, I don’t ‘do’ ObjectiveC for a living (but I may change my mind after completing this :)), so I would really appreciate the constructive feedback in making this plugin better, so I look forward to your comments and potential pull requests!

In my previous tutorial I showed how to create a native iOS app with Swift (ObjectiveC code also available) that can receive VoIP push notifications sent with Houston, custom PHP script or through Amazon SNS.

In this tutorial I’m going to present to you the Cordova plugin that does the same thing; it allows hybrid iOS applications to receive the VoIP push notifications.

Building Cordova plugins

I won’t go into the details of Cordova plugin building in this document. If you’re new to building Cordova plugins, you can check out this tutorial and official docs, as they were indispensable in my quest to learn as much as possible about it.

plugin.xml

<?xml version='1.0' encoding='utf-8'?>
<plugin id="com.nikola-breznjak.voippush" version="1.0.0" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
    <name>VoIPPushNotification</name>
    <js-module name="VoIPPushNotification" src="www/VoIPPushNotification.js">
        <clobbers target="VoIPPushNotification" />
    </js-module>

    <platform name="ios">
        <config-file target="config.xml" parent="/*">
            <feature name="VoIPPushNotification">
                <param name="ios-package" value="VoIPPushNotification" />
            </feature>
        </config-file>

        <header-file src="src/ios/VoIPPushNotification.h" />
        <source-file src="src/ios/VoIPPushNotification.m" />
    </platform>
</plugin>

In this file you basically define:

  • for which platform is this plugin (<platform name="ios">)
  • where the source files of your plugin will be (header-file and source-file elements)
  • where is the JavaScript file that will be the bridge from Cordova to native code (js-module tag src property)
  • what will be the plugins name by which you’ll reference it in the Cordova/Ionic code (<clobbers target="VoIPPushNotification" />)

www/VoIPPushNotification.js

This file, stripped of it’s comments is very short (75 LOC):

var exec = cordova.require('cordova/exec');

var VoIPPushNotification = function() {
    this._handlers = {
        'registration': [],
        'notification': [],
        'error': []
    };

    // triggered on registration and notification
    var that = this;
    var success = function(result) {
        if (result && result.registration === 'true') {
            that.emit('registration', result);
        }
        else if (result) {
            that.emit('notification', result);
        }
    };

    // triggered on error
    var fail = function(msg) {
        var e = (typeof msg === 'string') ? new Error(msg) : msg;
        that.emit('error', e);
    };

    // wait at least one process tick to allow event subscriptions
    setTimeout(function() {
        exec(success, fail, 'VoIPPushNotification', 'init');
    }, 10);
};

VoIPPushNotification.prototype.on = function(eventName, callback) {
    if (this._handlers.hasOwnProperty(eventName)) {
        this._handlers[eventName].push(callback);
    }
};

VoIPPushNotification.prototype.off = function (eventName, handle) {
    if (this._handlers.hasOwnProperty(eventName)) {
        var handleIndex = this._handlers[eventName].indexOf(handle);
        if (handleIndex >= 0) {
            this._handlers[eventName].splice(handleIndex, 1);
        }
    }
};

VoIPPushNotification.prototype.emit = function() {
    var args = Array.prototype.slice.call(arguments);
    var eventName = args.shift();

    if (!this._handlers.hasOwnProperty(eventName)) {
        return false;
    }

    for (var i = 0, length = this._handlers[eventName].length; i < length; i++) {
        var callback = this._handlers[eventName][i];
        if (typeof callback === 'function') {
            callback.apply(undefined,args);
        } else {
            console.log('event handler: ' + eventName + ' must be a function');
        }
    }

    return true;
};


module.exports = {
    init: function(options) {
        return new VoIPPushNotification(options);
    },

    VoIPPushNotification: VoIPPushNotification
};

This code follows the structure of the phonegap-plugin-push push.js.

Once you call the init method, you get the new VoIPPushNotification object which then exposes the methods for listening to the registration, notification and error events.

src/ios/VoIPPushNotification.h

#import <Cordova/CDV.h>
#import <PushKit/PushKit.h>

@interface VoIPPushNotification : CDVPlugin <PKPushRegistryDelegate>

@property (nonatomic, copy) NSString *VoIPPushCallbackId;
- (void)init:(CDVInvokedUrlCommand*)command;

@end

Since we’re writing in ObjectiveC, we need to define the functions in the .h file. Here we do few things:

  • import Cordova and PushKit
  • add an instance property VoIPPushCallbackId
  • add an init function declaration

src/ios/VoIPPushNotification.m

#import "VoIPPushNotification.h"
#import <Cordova/CDV.h>

@implementation VoIPPushNotification

@synthesize VoIPPushCallbackId;

- (void)init:(CDVInvokedUrlCommand*)command
{
  self.VoIPPushCallbackId = command.callbackId;
  NSLog(@"[objC] callbackId: %@", self.VoIPPushCallbackId);

  //http://stackoverflow.com/questions/27245808/implement-pushkit-and-test-in-development-behavior/28562124#28562124
  PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
  pushRegistry.delegate = self;
  pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}

- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{
    if([credentials.token length] == 0) {
        NSLog(@"[objC] No device token!");
        return;
    }

    //http://stackoverflow.com/a/9372848/534755
    NSLog(@"[objC] Device token: %@", credentials.token);
    const unsigned *tokenBytes = [credentials.token bytes];
    NSString *sToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                         ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                         ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                         ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];

    NSMutableDictionary* results = [NSMutableDictionary dictionaryWithCapacity:2];
    [results setObject:sToken forKey:@"deviceToken"];
    [results setObject:@"true" forKey:@"registration"];

    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:results];
    [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; //[pluginResult setKeepCallbackAsBool:YES];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:self.VoIPPushCallbackId];
}

- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
{
    NSDictionary *payloadDict = payload.dictionaryPayload[@"aps"];
    NSLog(@"[objC] didReceiveIncomingPushWithPayload: %@", payloadDict);

    NSString *message = payloadDict[@"alert"];
    NSLog(@"[objC] received VoIP msg: %@", message);

    NSMutableDictionary* results = [NSMutableDictionary dictionaryWithCapacity:2];
    [results setObject:message forKey:@"function"];
    [results setObject:@"someOtherDataForField" forKey:@"someOtherField"];

    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:results];
    [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:self.VoIPPushCallbackId];
}

@end

In the implementation file we define our functions. The first one is init, and here we basically register for VoIP push notifications by using PKPushRegistry.

Then, to satisfy that, we implement two functions: didUpdatePushCredentials and didReceiveIncomingPushWithPayload.

The first one is triggered with the device token, which we then send back to the ‘JS world’. We listen for this in our Ionic/Cordova apps and send this information to our backend so that later when we’re going to send the push we know to which device id.

The second one is triggered when we receive the actual VoIP push notification. In this example, we take out the message (@alert) and return it to the ‘JS world’. In my particular case, this can be a message with a certain keyword, so that then I know what to do in my app based on that keyword.

Again, I have to stress here that you may wanna alter this to your liking and process even more data which you receive through the VoIP push notification.

Conclusion

I hope this plugin will come handy to you. Also, I hope that this will give you enough information so that you’ll be dangerous enough to go and fiddle with the code yourself.

As I’ve mentioned before, I would really appreciate the constructive feedback so that we can make this plugin better, so I look forward to your comments and optional pull requests.

Btw, I updated these posts with this solution:

  • StackOverflow post
  • Ionic framework forum
  • phonegap-plugin-push plugin

and I have also asked the main maintainer of phonegap-plugin-push plugin if this would make sense to put as a PR on that plugin.

I will update you on the progress of all this, and till then – code on!

#Cordova plugin for #VoIP push notifications https://t.co/jkn56YWGTU

— Nikola Brežnjak (@HitmanHR) September 30, 2016

iOS

How to create a native iOS app that can receive VoIP push notifications

TL;DR

In this tutorial, I’ll give you step by step instructions on how to create a native iOS app with Swift (ObjectiveC code also available in the Github repo) that can receive VoIP push notifications sent with Houston, custom PHP script or through Amazon SNS.

This tutorial is largely inspired by this one (one of the few that actually made sense and made the steps manageable). However, I’ve added some not so obvious steps and fixed the issues that I had with the newest versions. Also, I added the link to the finished project on Github for further reference.

VoIP notifications

The official documentation can be found here. Few of the advantages are:

  • app is automatically relaunched if it’s not running when a VoIP push is received
  • device is woken up only when VoIP push occurs (saves battery)
  • VoIP pushes go straight to your app for processing and are delivered without delay
  • app is automatically relaunched if it’s not running when a VoIP push is received

Prerequisite settings

Apple provides us with a framework called PushKit to support using this VoIP push feature. However, we need to configure some additional settings to get this working.

Creating an App ID

In case you don’t already have an app (and consequently an App ID), you need to create one.

First, login to your Apple developer account and access Certificates, Identifier & Profiles:

Next, go to Identifiers->App IDs and then click on the + button.

Two important things to fill out here are App ID Description and so-called Bundle ID (this will most likely be something like com.yourdomain.yourappname):

Although not seen in the screenshots above, I used nikolaVoipTest as Bundle ID. This will be important in the next step.

Generating a VoIP push certificate

To generate a VoIP push certificate you first need to click on the All button in the Certificates section on the left-hand side. Then, click the + button:

On the next page you need to select the VoIP Services Certificate:

and on the one after that you need to select the App ID for which you’re creating this VoIP certificate:

Next, you’ll be presented with instructions on how to create a so-called CSR (Certificate Signing Request) file:

Once you create that file, you’ll select it for upload on the next screen. If everything goes well you’ll be given the certificate which you have to download:

After you download the certificate, open it up, and this should open the Keychain Access application, and you should see the certificate under the My Certificates section:

Creating the app

With all the setting out of our way, we can now start Xcode and create a new Single view application project:

Take special care when setting the Product Name as the Bundle Identifier is set automatically from it. We need to set this to be the same as the Bundle identifier that we’ve set in the steps above.

Setting the appropriate capabilities

To use the VoIP push in the app, we need to turn ON the Background Modes for our app and check few of the checkboxes:

Make sure you select the following options:

  • Audio, Airplay, and Picture in Picture
  • Voice over IP
  • Background fetch
  • Remote notifications

Adding the code

Open AppDelegate.swift and at the top add the import PushKit statement.

Then, in the didFinishLaunchingWithOptions part of the application function make sure you register for notifications like this:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        //Enable all notification type. VoIP Notifications don't present a UI but we will use this to show local nofications later
        let notificationSettings = UIUserNotificationSettings(forTypes: [.Badge, .Sound, .Alert], categories: nil)

        //register the notification settings
        application.registerUserNotificationSettings(notificationSettings)

        //output what state the app is in. This will be used to see when the app is started in the background
        NSLog("app launched with state \(application.applicationState)")

        return true
}

Since we are using the registerUserNotificationSettings method we need to implement it’s delegate callback application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings):

func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {

    //register for voip notifications
    let voipRegistry = PKPushRegistry(queue: dispatch_get_main_queue())
    voipRegistry.desiredPushTypes = Set([PKPushTypeVoIP])
    voipRegistry.delegate = self;
}

In this callback, we register the VoIP notifications since we know that the user has agreed to receive notifications (since this function has been called). We enabled VoIP notifications by declaring the voipRegistry object.

At this point, you will get an error on the voipRegistry.delegate = self; line saying Cannot assign a value of type 'AppDelegate' to type 'PKPushRegistryDelegate!'.

The delegate for voipRegistry is of type PKPushRegistryDelegate which has three methods, two of which are required (didUpdatePushCredentials and didReceiveIncomingPushWithPayload). We have to define a so-called extension of the AppDelegate class. We do that by adding the following code after all the current code in the AppDelegate.swift file:

extension AppDelegate: PKPushRegistryDelegate {

    func pushRegistry(registry: PKPushRegistry!, didUpdatePushCredentials credentials: PKPushCredentials!, forType type: String!) {

        //print out the VoIP token. We will use this to test the notification.
        NSLog("voip token: \(credentials.token)")
    }

    func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {

        let payloadDict = payload.dictionaryPayload["aps"] as? Dictionary<String, String>
        let message = payloadDict?["alert"]

        //present a local notifcation to visually see when we are recieving a VoIP Notification
        if UIApplication.sharedApplication().applicationState == UIApplicationState.Background {

            let localNotification = UILocalNotification();
            localNotification.alertBody = message
            localNotification.applicationIconBadgeNumber = 1;
            localNotification.soundName = UILocalNotificationDefaultSoundName;

            UIApplication.sharedApplication().presentLocalNotificationNow(localNotification);
        }

        else {

            dispatch_async(dispatch_get_main_queue(), { () -> Void in

                let alert = UIAlertView(title: "VoIP Notification", message: message, delegate: nil, cancelButtonTitle: "Ok");
                alert.show()
            })
        }

        NSLog("incoming voip notfication: \(payload.dictionaryPayload)")
    }

    func pushRegistry(registry: PKPushRegistry!, didInvalidatePushTokenForType type: String!) {

        NSLog("token invalidated")
    }
}

After adding this extension you will note that the previously mentioned error disappears.

In the first function, we merely output the device token. We will need this token in the next section when we’ll be testing our app with sending VoIP push notifications.

In the second one we ‘act’ on the received VoIP push notification. In this concrete case, we show a local notification if the app is in the background or an alert if we’re in the app. The third function (didInvalidatePushTokenForType) is used for handling when the token is invalidated.

Testing VoIP notifications

We have several options for testing our app. I’ll cover few of them in this section:

  • CLI program called Houston
  • PHP script called SimplePush
  • Amazon SNS

Getting the device token

Run your app in Xcode and make sure you run it on an actual device. The console output should look something like this:

2016-09-19 10:08:53.793
voipTestNikola[1876:2020432]
app launched with state UIApplicationState

2016-09-19 10:08:53.877
voipTestNikola[1876:2020432]
voip token: <40cc4209 d0f3ac25 95a7e937 3282897b 211231ef ba66764c 6fd2befa b42076cb>

Take note of the voip token from the output above (of course, the one from your Xcode debug window and not the one I’ve pasted above ;)), as we’ll need it in the next sections.

Preparing the certificate file

The VoIP certificate file that we’ve downloaded and added to the KeyChain has to be converted to a different file format so that we’ll be able to use it with the tools and services that I’ve listed above.

First, you need to open the KeyChain app on your Mac and then Export (Right click then select Export) the certificate:

You will get a .p12 file.

Now, navigate to the folder where you exported this file and execute the following command:

openssl pkcs12 -in YOUR_CERT.p12 -out VOIP.pem -nodes -clcerts

This will generate VOIP.pem file which we’ll use in the next sections.

Houston

Even though the docs say you can install it simply with gem install houston, you will most likely end up (after some StackOverflow searching) using this command to install it:

sudo gem install -n /usr/local/bin houston

This way you’ll install it to your local bin directory to which you have full rights.

Houston installed one more tool that will help us send the notifications like this:

With Terminal navigate to the folder where you have your certificate, copy the device id from above and execute a command like this:

apn push "<40cc4209 d0f3ac25 95a7e937 3282897b 211231ef ba66764c 6fd2befa b42076cb>" -c VOIP.pem -m "Testing VoIP notifications!"

Please note to change the VOIP.pem to whatever you named the file in the steps above.

You should get the following output in your terminal:

And, you should see this on your phone in case it was in the foreground:

In case the app was in the background you should see:

Also, I made a short video showcasing how the app behaves when it’s closed and receives a VoIP push (it’s woken up and run).

SimplePush

SimplePush (simplepush.php in the project root directory) is a PHP script that can be found on the net in few various forms and from few various authors. However, the code is less then 50 LOC, so it’s quite simple to understand. We need to set just a few of the config options:

// Put your device token here (without spaces):
$deviceToken = 'deviceToken';

// Put your private key's passphrase here:
$passphrase = 'passphrase';

// Put your alert message here:
$message = 'message';

// Put the full path to your .pem file
$pemFile = 'pemFile.pem';

and then run the script with php simplepush.php.

The only thing to note here is that we need to insert the device token without spaces and without < and > characters.

Amazon SNS

Amazon has really good documentation for preparing everything you need, and you can take a look at it here.

After you have all the prerequisites, you should follow these instructions to create the so-called ‘platform application’. Settings that I’ve used are on the image below:

After this you can add a platform endpoint by pasting your device id (again, as in the PHP example; without spaces and < and > characters).

Finally, you have to select this endpoint and click on the Publish to endpoint button:

Here you can enter some test data like shown below:

After you click on the Publish message you should get a notification on your phone.

Conclusion

In this tutorial you’ve learned how to create a native iOS app with Swift that can receive VoIP push notifications sent with Houston, custom PHP script or through Amazon SNS.

I bolded native for a reason in the sentence above. As you know, I’m a big fan of hybrid apps and Ionic framework in particular.

This post is a part of the recent task that I had to do to create the Cordova VoIP push plugin. To successfully complete that, I first made the native app and then the plugin, since (unfortunately) the plugin wasn’t available.

You can read all about how I created the Cordova plugin for receiving VoIP push notifications in this post.

How to create a #native #iOS app that can receive #VoIP push notifications https://t.co/PFGq7rqXZr

— Nikola Brežnjak (@HitmanHR) September 30, 2016

Angular 2

How to use http in Angular 2 via angular-cli?

I initially tested and wrote a tutorial for Pluralsight by using the angular-cli version 1.0.0-beta.9.

However, I’ve tried today with the latest version and for the life of me I couldn’t figure out how to use HTTP to call some service.

In the end, I figured what the issue was, so I’m putting it out here so it may be useful to someone else as well.

So, when I installed angular-cli with npm install -g angular-cli I haven’t at first noticed this error:
UNMET PEER DEPENDENCY [email protected]

What I ended up doing now was

npm install webpack -g && npm install webpack --save-dev

and now I can normally include Http into my component like this:

import { Http, Response } from '@angular/http';

and then use it within a class like this:

Hope this helps someone.

Ionic

3rd Ionic framework meetup in Čakovec

Yesterday I held the third Ionic framework meetup in Čakovec titled Getting started with Angular 2.

I showed how to get started with Angular 2 by using the angular-cli project to start, scaffold and test Angular 2 applications. You can read the tutorial that this talk was based on here: Getting started with Angular 2 by building a Giphy search application.

Two pics from the meetup:

thumb_img_7241_1024

thumb_img_7243_1024

I would like to thank Goran Levačić, the leader of incubation and education in TICM, for securing us the place for this meetup and company Axiom for the provided drinks.

In case you’re interested in next events, be sure to check out the meetup page and join the discussion there.

Page 21 of 51« First...10«20212223»304050...Last »

Recent posts

  • Discipline is also a talent
  • Play for the fun of it
  • The importance of failing
  • A fresh start
  • Perseverance

Categories

  • Android (3)
  • Books (114)
    • Programming (22)
  • CodeProject (35)
  • Daily Thoughts (77)
  • Go (3)
  • iOS (5)
  • JavaScript (127)
    • Angular (4)
    • Angular 2 (3)
    • Ionic (61)
    • Ionic2 (2)
    • Ionic3 (8)
    • MEAN (3)
    • NodeJS (27)
    • Phaser (1)
    • React (1)
    • Three.js (1)
    • Vue.js (2)
  • Leadership (1)
  • Meetups (8)
  • Miscellaneou$ (77)
    • Breaking News (8)
    • CodeSchool (2)
    • Hacker Games (3)
    • Pluralsight (7)
    • Projects (2)
    • Sublime Text (2)
  • PHP (6)
  • Quick tips (40)
  • Servers (8)
    • Heroku (1)
    • Linux (3)
  • Stack Overflow (81)
  • Unity3D (9)
  • Windows (8)
    • C# (2)
    • WPF (3)
  • Wordpress (2)

"There's no short-term solution for a long-term result." ~ Greg Plitt

"Everything around you that you call life was made up by people that were no smarter than you." ~ S. Jobs

"Hard work beats talent when talent doesn't work hard." ~ Tim Notke

© since 2016 - Nikola Brežnjak