E: me@sabisin.com | T: +4915168651209

Configuring App Transport Security Exceptions in iOS 9 and OSX 10.11

If your app (a third-party web browser, for instance) needs to load arbitrary content, Apple provides a way to disable ATS altogether, but I suspect it’s wise for you to use this capability sparingly:

<key>NSAppTransportSecurity</key>
<dict>
  <!--Include to allow all connections-->
  <key>NSAllowsArbitraryLoads</key>
      <true/>
</dict>

gameon

Install an IPA on iOS directly from a URL

Upload your IPA on a FTP. Then create a plist file with this format:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>items</key>
    <array>
        <dict>
            <key>assets</key>
            <array>
                <dict>
                    <key>kind</key>
                    <string>software-package</string>
                    <key>url</key>
                    <string>https://sabisin.com/myApp.ipa</string>
                </dict>
            </array>
            <key>metadata</key>
            <dict>
                    <key>bundle-identifier</key>
                    <string>com.sabisin.myApp</string>
                    <key>bundle-version</key>
                    <string>1.0</string>
                    <key>kind</key>
                    <string>software</string>
                    <key>title</key>
                    <string>MyGame</string>
            </dict>
        </dict>
    </array>
</dict>
</plist>

Change the url, app id and title name. Then create a simple HTML page:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
    <head>
        <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
        <title>Install MyGame</title>
        <style>
            html, body { height:100%; }
        </style>
    </head>
    <body>
        <br/>
        <div style="text-align:center;">
            <h3>Install myApp</h3>
        </div>
        <div style="text-align:center;">
            <img src="icon_57.png" border="0" align="center"></img>
        </div>
        <br/>
        <div style="text-align:center;">
            <a href="itms-services://?action=download-manifest&url=https://sabisin.com/myApp.plist">Install myApp</a>
        </div>
        <br/>
    </body>
</html>

You must have your plist file on a https server.

Google Cloud Storage Cross Domain Policy Access.

There are times when you have a Flash application, and you’d like that Flash application to access the files in your Google Cloud Storage, but we all know that accessing Google Cloud Storage files would violate cross-domain policies. Now, Google owns the domain which means we can’t exactly change their crossdomain.xml, however, they do give each bucket a subdomain which means that we can have our own crossdomain.xml specified!

Here’s what you have to know:
Domains in terms of cross domain policies are sensitive to subdomains, so x.y.a.asdfa.dsfad.google.com has its own crossdomain policy (or none at all). However, commondatastorage.googleapis.com/crossdomain.xml does not exist which means we cannot override that crossdomain policy. That’s the annoyance.

However, rejoice, because your-bucket-name.commondatastorage.googleapis.com/crossdomain.xml exists, all you have to do is upload a crossdomain.xml policy to the root of your bucket directory, and then always access files in your Flash application using the above domain.
Note: http://commondatastorage.googleapis.com/your-bucket-name/… will not work because it is a different sub domain, and therefore different cross domain policies.

Make sure you do the following inside your Flash application:

Security.allowDomain(your-bucket-name.commondatastorage.googleapis.com);

Mario Mushroom: Now with 80% less awesome

tl;dr: Don’t use the Mario Mushroom Operator if you don’t want your setter to be invoked more than once.

Update: I totally forgot to mention that I found out about this problem with @darscan while working on Swiftsuspenders and Robotlegs code.

The Details I think it was @robpenner who coined the term “Mario Mushroom Operator”.

In case you’re wondering, the Mario Mushroom Operator is this: ||=.

A good translation for how the MMO™ works seems to be this:

if (!field) { field = value; }

In case you’re still wondering, here’s how you’d use it:

function useRuntimeDefault(input:Object):void { 
   input ||= getDefaultValue(); 
}

I.e., the most important use-case for the MMO™ is to apply runtime-determined default values for method arguments.

Now, that’s really useful and you might be wondering what could possibly go wrong with that.

Consider this snipped of code:

private var _setOnce : Boolean; private var _value : Object;

public function set value(value : Object) : void { 
   if (_setOnce) { 
      throw new Error('Value can only be set once'); 
   } 
   _setOnce = true; 
   _value = value; 
}
public function get value() : Object { 
   return _value; 
}

Used in a class, this code encapsulates a value that can be set exactly once, after which it can only be read.

With me still? Splendid.

In fact, you’re probably already guessing what comes now: Using the MMO™ to assign this once-settable value iff it hasn’t already been set:

value ||= {};

And here, finally, things go awry. As it turns out, the MMO™’s translation given earlier isn’t quite correct. Instead, the compiler (or the VM, I haven’t checked the bytecode) seems to translate our usage of the MMO™ to something along the following lines:

field = field ? field : {};

In summary, instead of guarding the assignment to a field as an if statement would do, the MMO™ only chooses between two values to use in the assignment like the ternary operator does.

In case you’re now thinking that that doesn’t affect you because you, just as every sane person you know, don’t ever have use-cases for one-time assignable fields, ask yourself whether you can be certain that all your setters are side-effect free if you re-assign the same value and that you never, ever, care about the overhead associated with double-setting values needlessly. “Yes” and “yes”? Cool. “Mmh” and “not sure”: Weep with me.

iCloudANE

iCloudANE is a native extension that enables the use of iCloud storage service. The extension supports String Key-Value Stores, that can be combined with JSON to store complex data. The iCloud service allows iOS application to share information among different devices.

http://airextensions.net/shop/extensions/icloud-by-vitapoly/

Sample

var iCloud:iCloudANE = new iCloudANE();

// storing data
// so.data is some shared object data. but it can just be a generic string
iCloud.store("save", JSON.stringify(so.data));	

// retrieving data
var iCloudSave:String = iCloud.getStringForKey("save");

GameKit

GameKit is a native extension that allows the use of iOS GameKit framework. The extension allows your game to setup real time Game Center matches for up to 4 players, send and receive custom data between players, and enable voice chat during gameplay. It implements a subset of the iOS GameKit framework.

http://airextensions.net/shop/extensions/game-kit-by-vitapoly

Sample

var gamekit:GameKit = new GameKit();
 
// Authenticate the local player, but listen to the events first:
gamekit.addEventListener(GameKit.LOCAL_PLAYER_AUTHENTICATED_EVENT, function(e:Event):void {
    trace("LOCAL_PLAYER_AUTHENTICATED_EVENT");
});
 
gamekit.addEventListener(GameKit.LOCAL_PLAYER_NOT_AUTHENTICATED_EVENT, function(e:Event):void {
    trace("LOCAL_PLAYER_NOT_AUTHENTICATED_EVENT");
});
 
gamekit.authenticateLocalPlayer();
 
//Get info about local player after successful authentication:
var localPlayer:LocalPlayer = gamekit.getLocalPlayer();
trace(localPlayer.displayName);
 
for (var friend:Player in localPlayer.friends)
    trace("friend: " + friend.displayName);
 
//Show native Game Center interface:
gamekit.showGameCenter();
 
//Start a real time match, but listen to events first:
gamekit.addEventListener(GameKit.MATCH_MAKER_FAILED_EVENT, function(e:ErrorEvent):void {
    debug("MATCH_MAKER_FAILED_EVENT: " + e.errorID + ", " + e.text);
});
 
gamekit.addEventListener(GameKit.MATCH_MAKER_CANCELLED_EVENT, function(e:Event):void {
    debug("MATCH_MAKER_CANCELLED_EVENT");
});
 
gamekit.addEventListener(GameKit.MATCH_MAKER_FOUND_MATCH_EVENT, function(e:MatchFoundEvent):void {
    debug("MATCH_MAKER_FOUND_MATCH_EVENT: " + JSON.stringify(e));
 
    match = e.match; // save the match somewhere
    if (match.expectedPlayerCount == 0)
        startGame(); // start game if not expecting anymore players
});
 
// bring up native match making interface for a match with 2 to 4 players
gamekit.startRealTimeMatch(2, 4);
 
// Send data to other players during game:
var data:ByteArray = new ByteArray();
data.writeUTFBytes("hello");
 
// send a reliable packet to all players
match.sendDataToAll(data, true);
 
// send an unreliable packet to the match's first player
match.sendData(match.players[0], data, false);
 
// Receive data from other players:
match.addEventListener(RealTimeMatch.RECEIVED_DATA_EVENT, function(e:DataReceivedEvent):void {
    debug("RealTimeMatch.RECEIVED_DATA_EVENT from " + e.player.playerID + ": " + e.data.toString());
});
 
// Start a voice chat with other players:
var chat:VoiceChat = match.getVoiceChat("all");
 
// join the voice chat so the player can hear other players
chat.join();
 
// set talk to true so other players can hear this player
chat.talk = true;
 
// Disconnect and properly dispose the match:
match.disconnect();
match.dispose(); // releases the native match object

Hungry Hero goes Open Source

hUngaryhEro

Hungry Hero is an open source Flash game built on Starling Framework. This game is built to give developers an idea of how a typical Starling based game looks like. The basic idea is to showcase how easy it is to build a Stage3D game, giving your games the power of GPU rendering or Hardware acceleration.

http://www.hsharma.com/games/hungry-hero-goes-open-source/

Success is a catalyst for failure

Why don’t successful people become really successful? Greg McKeown explains in The Disciplined Pursuit of Less.

Why don’t successful people and organizations automatically become very successful? One important explanation is due to what I call “the clarity paradox,” which can be summed up in four predictable phases:

Phase 1: When we really have clarity of purpose, it leads to success.
Phase 2: When we have success, it leads to more options and opportunities.
Phase 3: When we have increased options and opportunities, it leads to diffused efforts.
Phase 4: Diffused efforts undermine the very clarity that led to our success in the first place.

Restart an AIR application

It takes an application ID and a publisher ID of the currently running application (that is, of itself), then attempts to launch the application with these IDs (that is, another instance of itself) and closes itself. Thus effectively doing a restart.

Also note that this will only work if ‘allowBrowserInvocation’ is set to true in application descriptor.

public function restart():void {
	new ProductManager("airappinstaller").launch("-launch " + NativeApplication.nativeApplication.applicationID + " " + NativeApplication.nativeApplication.publisherID);  
	NativeApplication.nativeApplication.exit(); 
}