Tag Archives: iOS

Access iOS Simulator Logs directly

Sometimes I need to get NSLogs from an app running in the iOS simulator, but said simulator wasn’t launched through Xcode.

There’s a method listed in this stackoverflow post that works for me with Xcode 6.

In the simulator itself, you go to Debug > Open System Log… and it should open Console.app and come right up. If it doesn’t, you might need to try it more than once like I had to.

Screenshot 2015-09-28 20.41.55

If you want to access the log files directly on disk, it’s a bit convoluted. Direct quote from the stackoverflow page (in case link rot sets in):

In case you need it, this log is kept in Library/Logs/CoreSimulator/[device name]/system.log. To get [device name], go to Xcode, Window -> Devices and find the device that you are currently simulating. Look for the Identifier. Compare that against the folder names in Library/Logs/CoreSimulator and you should find a match.

Self-hosted adhoc IPA delivery of iOS apps

Although this may be old hat for many, I recently learned this from an iOS project I’ve been working on.

With the acquisition of Testflight by Apple, you can now do iOS beta-testing directly through iTunes Connect, and you don’t need device UDIDs to get your adhoc IPAs on your testers’ devices. But what if, like this recent project, you have to target iOS 7 (Testflight beta testing from Apple only works on iOS 8 and up)? And what if you don’t want to wait for Apple’s beta review process before a beta app goes out?

In that case, you can host your adhoc IPAs for download on your own server. First you have to do the old process of getting device UDIDs from your testers, entering them into iTunes connect, and creating a distribution provisioning profile with those devices enabled.

Once you’ve done all that, and you’ve created your adhoc IPA, you can go ahead and upload that file to your server. Remember where you put it, because you’ll need the full URL to your ipa in the next steps.

Create a .plist file on your server with the following data in it. You’ll need to enter the full URL to your IPA, the bundle ID of your app, its current version, and its name. Make sure to remove the brackets from the code below when entering your values.

Sample .plist file:

<?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>[http://yourserver.com/path/to/ipa]</string>
				</dict>
			</array>
			<key>metadata</key>
			<dict>
				<key>bundle-identifier</key>
				<string>[com.yourcompany.yourgame]</string>
				<key>bundle-version</key>
				<string>c[urrent version of your app]</string>
				<key>kind</key>
				<string>software</string>
				<key>title</key>
				<string>[name of your app]</string>
			</dict>
		</dict>
	</array>
</dict>
</plist>

Save that as a .plist file, and upload it to your server. Remember the full URL to the .plist file.

Next, create a HTML file on your server with the following code in it, replacing the part with the full URL to your plist:

<a href="itms-services://?action=download-manifest&url=http://yourserver.com/path/to/plist">click here to install<a>

Navigate to that page on your device, click the link, and it should work! (assuming the adhoc provisioning profile you built your app with contains permissions for your device)

ANE for iOS with Custom Framework – Using Custom Fonts

We’re developing a set of games for iOS, some objective-C and some using Adobe AIR, and we’re using an iOS custom framework to hold a bunch of storyboard-based screens that we want to use across all the apps.

On the AIR side, we’ve created an Adobe Native Extension and figured out how to include our framework in it. This may be a subject for another blog post, because it was quite complicated, but this post really helped us figure out how to get all the images, storyboards, and sound files (among other assets) to get included in the ANE, and thus into the final app. We also used it to include our custom font file that the storyboards made heavy use of.

However, this was not enough. Using this post, I was able to troubleshoot all the possible steps that could go wrong. I had to make sure that the .ttf file got included in the final output of the framework, but the real key was Step 4 – adding the font information to your app’s info.plist file. Since an ANE is NOT an app, these keys need to go in the info.plist of the final app the ANE gets included in. But AIR apps use an Application Descriptor File, not an info.plist file. The info.plist file of the completed .IPA is auto-generated when the app is built.

Not to worry, Adobe has provided a place in said app descriptor file where you can specify items to add to the auto-generated info.plist. Appropriately enough, it’s called the InfoAdditions element. The content of this element must be wrapped in CDATA tags, and anything inside it will be added to the info.plist of the final app. So, in an XCode sample app, I followed step 4 above and created the required key/value in XCode’s graphical plist editor, and then opened the generated file in a text editor and copy/pasted those values. Here’s what I got:

<key>UIAppFonts</key>
<array>
	<string>name-of-your-font.ttf</string>
</array>

And here’s what that looks like pasted into an InfoAdditions tag in the app descriptor:

<iPhone>
	<InfoAdditions><!&#91;CDATA&#91;
		<key>UIAppFonts</key>
		<array>
			<string>name-of-your-font.ttf</string>
		</array>
	&#93;&#93;></InfoAdditions>
</iPhone>

I’ve omitted lots of other things that are in my descriptor for brevity – keys specifying minimum iOS version, custom URL schemes, which devices the app targets – but you get the idea.

Once I had this all put together, it worked like a charm! Our storyboards look great as ever with their custom fonts!

AIR for iOS Runtime Error #1520: Mutex cannot be initialized.

Situation: I’m making an app for iOS and Android using Flash Builder 4.7 and AIR SDK 4.0. It includes the Lua 5.2 interpreter as compiled from C code into a SWC using CrossBridge (formerly FlasCC). I’m just using the lua.swc file from the crossbridge samples. However, apparently there’s some problem with the multithreading code or something (is multithreading even supported in AIR 4.0? I don’t remember), because I get the following run-time error when debugging on the device (not on Android or AIR simulator, just iOS):

Error #1520: Mutex cannot be initialized.

Solution: I don’t know why this works, but if you add the following compiler options:

--swf-version=17

It works. This probably means I’m targeting an older flash player and one day I will need to figure out how to get the Lua interpreter code.

Here’s a pretty picture of the box where you enter the code in Flash Builder 4.7:
version17

Supporting “the other landscape” in AIR for iOS

Most iOS games are either portrait-only or landscape-only. The AIR application descriptor file lets you easily specify this. All you have to do is add the following to your descriptor file, inside the initialWindow tag:

<aspectRatio>landscape</aspectRatio>
<autoOrients>false</autoOrients>

The above configuration will result in a landscape app that will be right-side up when the home button is on the right – known as “landscape right” – that doesn’t rotate to portrait when the device is turned. However, it will ALSO not rotate when the device is turned to “the other landscape orientation” – if you position your iDevice so that the home button is on the left, your app will be upside-down!

To have a truly industry-standard game, you’ll want your portrait games to support both “Default” and “Upside Down”, and your landscape games to support both “Landscape Left” and “Landscape Right”, as Apple calls them:
iphone_orientations

To accomplish this, we need to think about the concept of “stage orientation” as opposed to “device orientation”. Adobe’s StageOrientation class defines four orientations – DEFAULT, ROTATED_LEFT, ROTATED_RIGHT, and UPSIDE_DOWN. These orientations describe the orientation of the Flash stage relative to the physical device. DEFAULT simply means that the stage is oriented to match the physical orientation of the device. ROTATED_RIGHT and ROTATED_LEFT mean the stage is rotated either 90 degrees right or left. UPSIDE_DOWN means the stage is rotated 180 degrees.

For our game to work properly, we want to allow the stage to be in either the DEFAULT or UPSIDE_DOWN orientations, but NOT the ROTATED_LEFT or ROTATED_RIGHT orientations. Fortunately, Adobe has added some events that help us do just that. If your app descriptor has autoOrients set to true, the StageOrientationEvent.ORIENTATION_CHANGING event will be broadcast when the device’s accelerometer has detected the physical orientation has changed, and the Stage is about to rotate to follow suit. If you call Event.preventDefault(), you will prevent the Stage from rotating. So all we have to do is disallow rotating to the left or right, and allow rotating to the upside-down or default positions.

To accomplish this, add the following to your application descriptor file, to enable the Stage to rotate to follow the device’s physical orientation:

<autoOrients>true</autoOrients>

And add this to your app’s main class, to only allow a subset of those rotations to actually take place:

// we can control which orientations we want to allow with the following code
stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGING, onOrientationChanging );

function onOrientationChanging( event:StageOrientationEvent ):void
{
	// If the stage is about to move to an orientation we don't support, let's prevent it
	// from changing to that stage orientation.
	if(event.afterOrientation ==
		StageOrientation.ROTATED_LEFT || event.afterOrientation ==
		StageOrientation.ROTATED_RIGHT )
		event.preventDefault();
}

And voila! Your app now support both portrait orientations, or both landscape orientations!

Condensed from http://www.adobe.com/devnet/flash/articles/screen_orientation_apis.html

Also helpful: https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/RespondingtoDeviceOrientationChanges/RespondingtoDeviceOrientationChanges.html