Guaranteed Instantiation in Javascript

quick one today.

Let’s say you like the constructor pattern for objects. You probably do something similar to this:

function Person(name) {
    var __ = this;
    
    __.name = name;
    
    return __;
}

Let’s say you forget to use the”new” operator to instantiate the function and instead just call it as is while trying to assign it to a variable:

var mike = Person('Mike');
name = 'john';

console.log(mike.name) // results in john

The problem is “this”. Without referring to the “new” keyword, the function’s “this” refers to the global “this”. When you call the function, it can collide with any other variable in the global scope.

Of course you can fix it by doing:

var mike = new Person('Mike');
name = 'john';

console.log(mike.name) // results in mike

Of course, this is the right way to do it. But how can you make sure that even if the user doesn’t call it correctly, your class doesn’t create crazy collisions and potentially cause someone to spend hours debugging?

Easy! Check your object scope. Figure out who you belong to and force instantiation otherwise:

function Person(name) {
    var __ = this;
    
    if(!(__ instanceof Person)) {
        return new Person(name);
    }
    
    __.name = name;
    
    return __;
}

Now your object will return an instance of itself, even if called the wrong way.

var mike = Person('Mike');
name = 'john';

console.log(mike.name) // still results in Mike

Bye!

Debugging Cordova Apps, My Way

Cordova is hard to debug. There are millions things that can go wrong and it hard to separate the easy to debug stuff from the rest once you start working with native. That’s why its important to make the parts that don’t depend on native functionality work in the browser first. Get it working, then when it’s finished, bring it into the native app and work from there. Here’s a quick video showing you what I mean:

If you’re interested in my grunt file here it is:

module.exports = function(grunt){

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        exec:{
        	prepare:{
        		command:"cordova build",
        		stdout:true,
        		stderror:true
        	}
        },
        copy: {
                main: {
                        expand: true,
                        cwd: 'www/',
                        src: ['*', '**/*'],
                        dest: 'browser/'
                },
                cordovasrc: {
                        expand: true,
                        cwd: 'cordova-browser-src/',
                        src: ['*', '**/*'],
                        dest: 'browser/'
                }
        },
        watch:{
        	files:['www/**/*.*', 'cordova-browser-src/**/*.*'],
        	tasks:['exec:prepare', 'copy']
        }
    });
        
        // watch the www folder and build cordorva
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-exec');
        // copy www to browser and load in cordova.js to test in browser
        grunt.loadNpmTasks('grunt-contrib-copy');

    grunt.registerTask('default', ['watch']);

};

And here’s the cordova.js file:

var cordova = { 
    init: function() {
        app.initialize();
        var event = new Event('deviceready');
        document.dispatchEvent(event);
    },
    plugins: {
        notification: {
            local: {
                on: function(listener, callback, context) {
                    document.addEventListener(listener, callback, context);
                },
                getAll: function(callback) {
                    var notifications = [];
                    callback(notifications);
                },
                hasPermission: function(callback) {
                    callback(true);
                },
                schedule: function() {
                    
                },
                cancel: function(id, callback) {
                    var notification = {
                        stuff: 'things',
                        id: id
                    };
                    callback(notification);
                },
                registerPermission: function(callback) {
                    callback(true);
                }
            }
        }
    },
    InAppBrowser: {
        open: function(url) {
            window.location = url;
        }
    }
};

var StatusBar = {
    hide: function() {
        return true;
    }
};

setTimeout(function() {
    cordova.init();
}, 1000);

It will fire a “deviceready” event to kick the whole thing off!

 

Uploading multiple APKs to the Play Store from Cordova and Crosswalk

Let’s say you have a low version release and a current release for your app. Let’s also say you’re using crosswalk or another plugin that builds for different device architectures. We can still do it!

It all depends the android version code. If you take a look in your android manifest you’ll see something like:

android:versionCode="102052"

Basically it’s a version code that (among other things) tells google play that this is a new APK. You need to increment this every time you upload a new APK, even if its meant to support the same version!

Here’s the code:

# in your config xml file
# add the following attribute to "widget"
# should look something like: <widget id="com.gsp.appName" version="1.2.5" android-versionCode="102052"
android-versionCode="102052"

# in your project root
cordova build --release android

# cd into your apk folder
cd platforms/android/build/outputs/apk

# if you havent already, generate a keystore file and save it someplace safe
# this file will allow you to make updates and sign your app, without it 
# you're screwed, so make sure you keep it. You can sign other apps with it.


# sign your apk with your keystore file
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ~/PATH/TO/FILE/your_key.keystore android-release-unsigned.apk alias_name

# now verify with zipalign
~/Library/Android/sdk/build-tools/23.0.0/zipalign -v 4 android-release-unsigned.apk YOUR_APP_NAME.apk

#once verified, upload it to the play store apks.

# increment the version code for your next apk
# should look like: <widget id="com.gsp.appName" version="1.2.5" android-versionCode="102053"
android-versionCode="102053"

# repeat the building through uploading steps, repeat as necessary

Here's a video to show you how to do it:

Publishing Your Cordova App to the Play Store

You’re done! Now you want to publish? There’s a great resource here: http://ionicframework.com/docs/guide/publishing.html

But I’ll repost the instructions here, in case the page goes away.

First you need to build for release:

cordova build --release android

If you have a keystore file already you can skip the next part. Basically, google requires you to sign the app, they will use this public key to verify you on your updates, so make sure you keep the .keystore file around:

keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000

Next you need to sign it with the keystore file:

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore HelloWorld-release-unsigned.apk alias_name

Now to the only trick part of this…

You need to “zipalign” your file:

zipalign -v 4 HelloWorld-release-unsigned.apk HelloWorld.apk

Just make sure you have access to the zipalign executable from your terminal, if you don’t you could do something like this:

~/Library/Android/sdk/build-tools/23.0.0/zipalign -v 4 HelloWorld-release-unsigned.apk HelloWorld.apk

If you’re on a Mac that should work. Now go to the play store console: https://play.google.com/apps/publish/

You need to pay $25 to get into their developer program, once you’ve done it, you should be able to create a new app and upload your apk that you generated above.

Git Tracking Remote Branches

For some reason, I’ve always failed to remember what the command to track a remote branch is in git. I look it up on this page everytime I want to do it: https://git-scm.com/book/en/v2/Git-Branching-Remote-Branches

Well no more. I figured if I write a post about it, I will remember it so here we go:

git fetch origin
git checkout -b somename origin/somename

That’s it… the branch will be set up to track the remote and you are switched over automatically.

Using the Facebook iOS SDK in Swift

Just a quick video to show you how to use the facebook native ios sdk in swift.

follow the directions to get your plist file updated here: https://developers.facebook.com/quickstarts/?platform=ios

Once that’s done follow the instructions to add your build identity to facebooks records. Then…

  1. drag the frameworks into your project
  2. update your appdelegate file
  3. update your view controller
  4. make your view controller a delegate for the login button
  5. test
AppDelegate.swift:

replace your applicationdidlaunchwithoptions:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
    }

Then add the following:

func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool {
        return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
    }

Then in your “applicationDidBecomeActive“:

FBSDKAppEvents.activateApp()

NOTE: make sure to import:

import FBSDKCoreKit
ViewController.swift:
//
//  ViewController.swift
//  FacebookTutorial
//
//  Created by Mike Newell on 8/13/15.
//  Copyright (c) 2015 Mike Newell. All rights reserved.
//

import UIKit
import FBSDKCoreKit
import FBSDKLoginKit

class ViewController: UIViewController, FBSDKLoginButtonDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        if FBSDKAccessToken.currentAccessToken() != nil {
            // user already has access token
            self.logUserData()
        } else {
            let loginButton = FBSDKLoginButton()
            loginButton.center = self.view.center
            loginButton.readPermissions = ["email"]
            self.view.addSubview(loginButton)
            loginButton.delegate = self
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    override func viewWillAppear(animated: Bool) {
        self.logUserData()
    }
    
    func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
        println("logged in")
    }
    
    func loginButtonDidLogOut(loginButton: FBSDKLoginButton!) {
        println("logged out")
    }
    
    func logUserData() {
        let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: nil)
        graphRequest.startWithCompletionHandler { (connection, result, error) -> Void in
            if error != nil {
                println(error)
            } else {
                println(result)
            }
        }
    }


}

That’s it! here’s a video explaining more:

There’s also a great tutorial for anyone looking to do the older “bridging” method of importing the sdk: http://www.brianjcoleman.com/tutorial-how-to-use-login-in-facebook-sdk-4-0-for-swift/