Skip to content →

diego.org Posts

Cocoapods – Unable to find a specification for

When trying to install CodableAlamofire, I kept getting this error

[!] Unable to find a specification for `CodableAlamofire` depended upon by…

I check and the pod existed in the CocoaPods Specs.  I also noticed it said it was updated (in this case added) 2 days ago:

The problem was that my CocoaPods was out of date.  I ran this command to update it:

pod repo update master

After updating and running pod install again, I was able to install it.

Installing CodableAlamofire (1.0.0)
Comments closed

D.L. Bliss Camping Tips

One of our favorite campsites is D.L. Bliss State Park. After camping there many times, here are a few tips we have learned over the years.

Map not to Scale. When you arrive and check in, the ranger will give you a map of the campsite. There are 3 main loops at Bliss and the beach. The map shows this. Make sure you note the text that says “Not to scale”. The loops are not close to each other. Our first time at Bliss we stayed at the top loop. We looked at the map and saw the beach was just below the 2 lower loops. We decided it would be a quick walk. We packed out gear and started walking down. Needless to say, it was not a quick walk. It’s walkable, just be aware.

Bear Boxes. All food and any scented item must go in the bear box (not your car). This includes soaps, lotions, gum, etc. There are bears. We’ve seen them. They are not as aggressive as in Yosemite, but do exist. Make sure all your stuff will fit in the bear box. The inside dimensions of the food lockers 36″ deep, 43″ wide, and 22″ high. Make sure your cooler(s) fits. And if you’re sharing, make sure whoever is sharing stuff will all fit together in 1 bear box.  Note: if you have a Yeti cooler or other bear-proof cooler, you can leave it outside the bear box as long as you have locks on it.

Ice. Tahoe gets warm during the summer. The metal bear boxes heat up in the sun and get really hot. The ice in your cooler melts quickly. Luckily the campsite host sells ice. When it’s hot, we refresh it daily.  Sometime the camp host will drive around in their ATV’s and sell ice and firewood. Fresh ice is also good if you want to plan on making cocktails.

Water, Bathroom and Showers. Each loop has a bathroom and showers. The showers take coins instead of quarters. You must buy these coins from the ranger kiosk when you enter the park. There are water spigots at about every couple of campsites. We drink the water from here. It’s drinkable and tastes good.

Beach. One of our favorite parts of D.L. Bliss is the beach. There is a small beach with a parking lot. One side of the beach is houses and the other side is rocks. On a busy day the beach will fill up fast. People come early and setup camp to reserve a spot on the beach. It’s best to go down around 7am and setup a spot on the beach. It’s best to setup a sunshade and some towels. If you’re early enough get one of the handful of picnic benches. There is a parking lot at the beach too. This also fills up quickly. On a busy day the lot is full by 8 or 9am. Another idea is to take your breakfast to the beach. You can setup on the beach and then make breakfast there or at the picnic tables by the parking lot.

Paddle Boards and Kayaks. Bliss is a great spot for Paddle Boards and Kayaks. There is a rocky cove just to the right of the beach. It’s fun spot to paddle around. The rocks are a popular spot for jumping into the water. It’s also popular with boats, so be careful.

Yellow Jackets. Towards the end of the camping season, the yellow jackets can be bad. One year (2016) was so bad we almost went home. The ranger suggested yellow jacket traps. We tried that and it didn’t do much. We found it best to just try and ignore them. They didn’t bite, but were just annoying.

Hiking. There are several good hikes around Bliss. The closest is the Rubicon Trail. It starts by the beach parking lot and is a 8.3 mile round trip to Emerald Bay. The gift shop at Emerald Bay sells popsicles and other packaged ice cream, which is a nice treat for the kids. Eagle Lake is another favorite hiking spot. The trailhead starts at the top of Emerald Bay. It’s a 1.8 mile round trip hike. There is a parking lot and you can park on the street, but during a busy weekend it fill early. I suggest being there by at least 8am. You start off by hiking next to a waterfall, then you cross it and then take a trail to Eagle Lake.  If you want to go further, there are lots of trails into Desolation Wilderness.

Cell Phone Reception.  There is some Cell Phone Reception at the lower campsites and beach.

South Lake Tahoe. It’s only 13 miles to South Lake Tahoe if you need to run out and get supplies.  With no traffic, this only takes about 25 minutes.  But on a busy weekend this could take over an hour.  The traffic gets bad because of people going to the beaches and Camp Richardson.  If you need to get out, I suggest doing it before 10am.

 

Comments closed

PHImageManager requestImageData with Photos iCloud Photo Library

I came across a bug the other day because of photos in the iCloud Photo Library. In my app I was showing a grid of images to be selected. If “iCloud Photo Library” was enabled then user could see the thumbnail and pick the image, but the app failed when it tried to do something with the image. This is because the image wasn’t downloaded yet.

This is what my code looked like.

let manager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.resizeMode = .exact
requestOptions.deliveryMode = .highQualityFormat;

// Request Image
manager.requestImageData(for: asset, options: requestOptions, resultHandler: { (data, str, orientation, info) -> Void in
	// Do somethign with Image Data
 })

I found the property: PHImageRequestOptions.isNetworkAccessAllowed. When enabled, the image is downloaded from iCloud. And you can set a progressHandler to inform the user.

I updated the code to look like:

let manager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.resizeMode = .exact
requestOptions.deliveryMode = .highQualityFormat;
requestOptions.isNetworkAccessAllowed = true;
requestOptions.progressHandler = { (progress, error, stop, info) in
    if(progress == 1.0){
        SVProgressHUD.dismiss()
    } else {
        SVProgressHUD.showProgress(Float(progress), status: "Downloading from iCloud")
    }
}

// Request Image
manager.requestImageData(for: asset, options: requestOptions, resultHandler: { (data, str, orientation, info) -> Void in
	// Do somethign with Image Data
 })

The requestImageData API, returns an info dictionary providing information about the status of the request. Documentation on the key is here:
PHImageManager -Image Result Info Keys

PHImageResultIsInCloudKey A Boolean value indicating whether the photo asset data is stored on the local device or must be downloaded from iCloud.

You could also check this key to see if downloading the image is required.

Comments closed

Embedding Crosswalk in Android Studio – UPDATED

This post is an updated version of the original one: http://diego.org/2015/01/07/embedding-crosswalk-in-android-studio/

Note: The Crosswalk team has stopped development on this project. You can read more about it here: Crosswalk 23 to be the last Crosswalk release

Crosswalk is a web runtime that replaces the built in WebView used by Android. Crosswalk is based on Google Chromium. Why use Crosswalk and not the built in WebView? The built in WebView varies greatly with each Android OS version. I’ve run into many problems because of the differences between the two. When you use Crosswalk you can work with a consistent WebView across all Android OS versions. Besides that, it has better HTML5 support. Read this article for more reasons “Why use Crosswalk for Android Builds?

The instructions for embedding Crosswalk in your application are based on ADT and they are complicated. Adding Crosswalk to Android Studio is much easier if you use the maven2 releases.

Here are steps for creating a new Android application in Android Studio and embedding Crosswalk.

Create a new Android Project

From the menu choose “File > New Project”

Give your application a name “CrosswalkDemo”

Give it a domain and project location and press “Next”.

Select “Phone and Tablet”, Minimum SDK “API 19” and press “Next”.

Select “Blank Activity” and press “Next”.

Use the defaults for the Activity name and press “Finish”.

Configure Crosswalk

Identify which Crosswalk release you want to install. You can find the releases here:
https://download.01.org/crosswalk/releases/crosswalk/android/maven2/

For this demo I choose version 20.50.533.12, which is found here:
https://download.01.org/crosswalk/releases/crosswalk/android/maven2/org/xwalk/xwalk_core_library/20.50.533.12/

Open the file:
CrosswalkDemo/app/build.gradle

First we need to add the Maven repository like this:

repositories {
    maven {
        url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'
    }
}

Then add this to your dependencies:

compile 'org.xwalk:xwalk_core_library:20.50.533.12'

The finished file should look like:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "org.diego.android.crosswalkdemo"
        minSdkVersion 19
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

repositories {
    maven {
        url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.0'
    compile 'org.xwalk:xwalk_core_library:20.50.533.12
}

Update the Code

Add an XWalkView to your layout like:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#000000">

    <org.xwalk.core.XWalkView
        android:id="@+id/xwalkWebView"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#000000"
        />

</LinearLayout>

In your activity, find the XWalkView and then load a url like:

xWalkWebView=(XWalkView)findViewById(R.id.xwalkWebView);
xWalkWebView.load("https://crosswalk-project.org", null);

And add these permissions to your AndroidManifest.xml

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

That’s pretty much it.

The entire activity looks like:

package org.diego.android.crosswalkdemo;

import android.os.Bundle;

import org.xwalk.core.XWalkActivity;
import org.xwalk.core.XWalkPreferences;
import org.xwalk.core.XWalkView;


public class MainActivity extends XWalkActivity {
    private XWalkView xWalkWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        xWalkWebView=(XWalkView)findViewById(R.id.xwalkWebView);

        // turn on debugging
        XWalkPreferences.setValue(XWalkPreferences.REMOTE_DEBUGGING, true);
    }

    @Override
    protected void onXWalkReady() {
        // Do anything with embedding API
        xWalkWebView.load("https://crosswalk-project.org", null);
    }

}

 

You can download a sample project here:
https://github.com/dougdiego/CrosswalkDemo

More details about the AAR Crosswalk release can be found here:
https://crosswalk-project.org/documentation/embedding_crosswalk/crosswalk_aar.html

Exclude x86 libraries

If you want to exclude x86 libraries for a smaller APK, then uncomment this code in build.gradle. This will only build armeabi-v7a libraries.

// Remove other libraries
ndk {
    abiFilters "armeabi-v7a"
}

64 Bit Build

Crosswalk creates the binaries for ARM 64 here: https://download.01.org/crosswalk/releases/crosswalk/android/maven2/org/xwalk/xwalk_core_library/20.50.533.12

To use one of these instead, first you need to download it:

curl -O https://download.01.org/crosswalk/releases/crosswalk/android/maven2/org/xwalk/xwalk_core_library/20.50.533.12/xwalk_core_library-20.50.533.12-arm64.aar

Then install it to your local maven repository:

mvn install:install-file -DgroupId=org.xwalk -DartifactId=xwalk_core_library \
      -Dversion=20.50.533.12-arm64 -Dpackaging=aar  \
      -Dfile=xwalk_core_library-20.50.533.12-arm64.aar \
      -DgeneratePom=true

Update your build.gradle to use your local maven repository:

repositories {
    mavenLocal()
}

Then you can reference it in your build.gradle:

compile 'org.xwalk:xwalk_core_library:20.50.533.12-arm64'
Comments closed

Exporting Evernote to Markdown

I have been a Evernote user since 2008.  I’ve only used it for text notes, even though Evernote supports much more.  I’ve never had a need to upgrade because my text notes never came anywhere near the upload limit.  In fact the thousands of text notes I currently have is only about 5mb, which is way less than the 60mb a month upload limit.

A month ago Evernote changed their plan so that you could only access it from 2 devices.  This was a problem for me because I used a computer at work, at home and my iPhone.  It wasn’t worth it to me to pay $34.99 a year to sync text documents.  Maybe if I used the other features.  I looked for another solution.

Ideally I wanted to keep all my notes in Markdown in Dropbox.  There’s a number of app which do this.  I settled on nvALT on the Mac and 1Writer on iOS.  Next I had to get my notes from Evernote to Dropbox as Markdown.  Evernote does not support this.  Evernote only supports exporting as HTML or Evernote XML Format (.enex).

Atter searching around I came across an open source project on GitHub called: ever2simple.  It was designed for exporting Evernote to SimpleNote.  This did most of what I needed, except it named all the files it exported sequentially like: 1.txt, 2.txt, 3.txt, …   This wouldn’t work for me because the name of my files means something to me.  I needed it to export the files with the title I gave it in Evernote.

So I forked it: https://github.com/dougdiego/ever2simple Now it exports the files and names them the title that was given in Evernote.  It also handles files with the same title.  Feel free to download this script and use it.  Just follow the instructions.

Comments closed

App Store Review Times – Automation?

Recently Apple shortened their review times from about 7 days to about 1 day.

You can follow the latest review times at appreviewtimes.com
appreviewtimes

How is Apple doing this? It could be new leadership. It could policy changes. It could be more people. While it may be all of these, I think it has something to do Automation.

Each year Apple has been getting better with their testing tools. In iOS 9, they made a big improvement with UI Testing tools. Xcode now allows you to record your UI Tests. Basically click a record button and then navigate your app in the Simulator. It’s a bit more complicated than that, but almost that easy.

What if Apple modified their testing tools, so the App Store Review team could record their review sessions. Once they have a recording for an app, they can run that recording on new submissions. If it passes, they approve the App. If it fails, they give the app a quick look through and fix the UI test.

They could have started recording session months in advance and then all of a sudden turned it on. If an App hadn’t been approved in a while or it was a new app, the first review would take longer. But after that, it would be fast.

I have no idea if this is what they are really doing, just fun speculation. I hope we’ll learn more at WWDC 2016.

Comments closed

Fastlane Frameit Tips

Here are few tips I learned when setting up Fastlane Frameit.

When I first ran fame it, I got this error:

$ frameit white

iconv: /Users/doug/src/my-ios-project/fastlane/screenshots/en-US/title.strings:1:252: incomplete character or shift sequence
[16:37:51]: Could not get title for screenshot ./iPhone6-0.png. Please provide one in your Framefile.json

iconv: /Users/doug/src/my-ios-project/fastlane/screenshots/en-US/title.strings:1:252: incomplete character or shift sequence
[16:37:52]: Could not get title for screenshot ./iPhone6-1.png. Please provide one in your Framefile.json

iconv: /Users/doug/src/my-ios-project/fastlane/screenshots/en-US/title.strings:1:252: incomplete character or shift sequence
[16:37:53]: Could not get title for screenshot ./iPhone6-2.png. Please provide one in your Framefile.json
ç
iconv: /Users/doug/src/my-ios-project/fastlane/screenshots/en-US/title.strings:1:252: incomplete character or shift sequence
[16:37:55]: Could not get title for screenshot ./iPhone6-3.png. Please provide one in your Framefile.json
√
iconv: /Users/doug/src/my-ios-project/fastlane/screenshots/en-US/title.strings:1:252: incomplete character or shift sequence
[16:37:56]: Could not get title for screenshot ./iPhone6-4.png. Please provide one in your Framefile.json

As the documentation clear states: “.strings files MUST be utf-16 encoded (UTF-16 LE with BOM).”

I fixed this by saving the file ast UTF-16 in TextWrangler.
textwrangler_utf-16

Then I ran into a strange error:

$ frameit white
[16:42:10]: `mogrify -gravity Center -pointsize 55 -draw text 0,0 'Text 1' -fill #000000 /var/folders/rf/yz3fgzq17sbgkjcxfq_x6lh40000gn/T/mini_magick20160324-45310-1yizv31.png` failed with error:
mogrify: unable to read font `(null)' @ error/annotate.c/RenderFreetype/1153.
mogrify: unable to read font `(null)' @ error/annotate.c/RenderFreetype/1153.
mogrify: non-conforming drawing primitive definition `text' @ error/draw.c/DrawImage/3165.

[16:42:12]: `mogrify -gravity Center -pointsize 55 -draw text 0,0 'Text 2' -fill #000000 /var/folders/rf/yz3fgzq17sbgkjcxfq_x6lh40000gn/T/mini_magick20160324-45310-qp00up.png` failed with error:
mogrify: unable to read font `(null)' @ error/annotate.c/RenderFreetype/1153.
mogrify: unable to read font `(null)' @ error/annotate.c/RenderFreetype/1153.
mogrify: non-conforming drawing primitive definition `text' @ error/draw.c/DrawImage/3165.

[16:42:13]: `mogrify -gravity Center -pointsize 55 -draw text 0,0 'Text 3' -fill #000000 /var/folders/rf/yz3fgzq17sbgkjcxfq_x6lh40000gn/T/mini_magick20160324-45310-eu9yaq.png` failed with error:
mogrify: unable to read font `(null)' @ error/annotate.c/RenderFreetype/1153.
mogrify: unable to read font `(null)' @ error/annotate.c/RenderFreetype/1153.
mogrify: non-conforming drawing primitive definition `text' @ error/draw.c/DrawImage/3165.

[16:42:15]: `mogrify -gravity Center -pointsize 55 -draw text 0,0 'Text 4' -fill #000000 /var/folders/rf/yz3fgzq17sbgkjcxfq_x6lh40000gn/T/mini_magick20160324-45310-1ie72eo.png` failed with error:
mogrify: unable to read font `(null)' @ error/annotate.c/RenderFreetype/1153.
mogrify: unable to read font `(null)' @ error/annotate.c/RenderFreetype/1153.
mogrify: non-conforming drawing primitive definition `text' @ error/draw.c/DrawImage/3165.

[16:42:16]: `mogrify -gravity Center -pointsize 55 -draw text 0,0 'Text 5' -fill #000000 /var/folders/rf/yz3fgzq17sbgkjcxfq_x6lh40000gn/T/mini_magick20160324-45310-ji9gyl.png` failed with error:
mogrify: unable to read font `(null)' @ error/annotate.c/RenderFreetype/1153.
mogrify: unable to read font `(null)' @ error/annotate.c/RenderFreetype/1153.
mogrify: non-conforming drawing primitive definition `text' @ error/draw.c/DrawImage/3165.

I came across a forum thread that said I needed to install ghostscript. So I installed Ghostscript with Homebrew like:

$ brew install gs
==> Installing dependencies for ghostscript: libtiff, little-cms2
==> Installing ghostscript dependency: libtiff
==> Downloading https://homebrew.bintray.com/bottles/libtiff-4.0.6.el_capitan.bottle.tar.gz
######################################################################## 100.0%
==> Pouring libtiff-4.0.6.el_capitan.bottle.tar.gz
🍺  /usr/local/Cellar/libtiff/4.0.6: 259 files, 3.4M
==> Installing ghostscript dependency: little-cms2
==> Downloading https://homebrew.bintray.com/bottles/little-cms2-2.7.el_capitan.bottle.tar.gz
######################################################################## 100.0%
==> Pouring little-cms2-2.7.el_capitan.bottle.tar.gz
🍺  /usr/local/Cellar/little-cms2/2.7: 16 files, 1M
==> Installing ghostscript
==> Downloading https://homebrew.bintray.com/bottles/ghostscript-9.18.el_capitan.bottle.tar.gz
######################################################################## 100.0%
==> Pouring ghostscript-9.18.el_capitan.bottle.tar.gz
🍺  /usr/local/Cellar/ghostscript/9.18: 709 files, 61M

Then it ran successfully:

$ frameit white
[16:45:21]: Added frame: '/Users/doug/src/my-ios-project/fastlane/screenshots/en-US/iPhone6-0_framed.png'
[16:45:23]: Added frame: '/Users/doug/src/my-ios-project/fastlane/screenshots/en-US/iPhone6-1_framed.png'
[16:45:25]: Added frame: '/Users/doug/src/my-ios-project/fastlane/screenshots/en-US/iPhone6-2_framed.png'
[16:45:28]: Added frame: '/Users/doug/src/my-ios-project/fastlane/screenshots/en-US/iPhone6-3_framed.png'
[16:45:30]: Added frame: '/Users/doug/src/my-ios-project/fastlane/screenshots/en-US/iPhone6-4_framed.png'
Comments closed

Managing where rows can be moved to in UITableView

In an app I was working on, I needed to prevent users from moving rows from section 1 to section 0. After reading the docs, I found Apple has just the API: Reordering Table Rows.

Here’s how I used the API. If the proposed destination section is 0, then return the current indexPath. As a result the user will be unable to draw a row from section 1 to section 0.

func tableView(tableView: UITableView, targetIndexPathForMoveFromRowAtIndexPath sourceIndexPath: NSIndexPath, toProposedIndexPath proposedDestinationIndexPath: NSIndexPath) -> NSIndexPath
{
    
    if proposedDestinationIndexPath.section == 0 {
        return sourceIndexPath
    }
    
    return proposedDestinationIndexPath;
}

My problem was simple, but this API could be used for all kinds of reordering problems.

Comments closed

Xcode 7 crashing when toggling Assistant editor

I had a Xcode project which was crashing whenever I tried to close the Assistant editor.  Here is what I did to fix it.

  1. Close the project in XCode
  2. Delete the following files using the Terminal.  Where “myproject” is the name your project.
rm -rf myproject.xcworkspace/xcuserdata

rm -rf myproject.xcodeproj/xcuserdata

rm -rf myproject.xcodeproj/project.xcworkspace

If you don’t feel comfortable using the Terminal, you can also right click on the file and choose “Show Package Contents” and delete the files.

If you don’t use CocoaPods, you may not have a myproject.xcworkspace

This solution may fix other Xcode crashing issues.

Comments closed

Migrate NSUserDefaults to App Groups – Swift

I needed migrate my NSUserDefaults to using App Groups. I came across this post Migrating to App Groups, which was doing exactly what I wanted in Objective-C. Here’s the version I rewrote in Swift:

func migrateUserDefaultsToAppGroups() {
	
	// User Defaults - Old
	let userDefaults = NSUserDefaults.standardUserDefaults()
	
	// App Groups Default - New
	let groupDefaults = NSUserDefaults(suiteName: "group.myGroup")
	
	// Key to track if we migrated
	let didMigrateToAppGroups = "DidMigrateToAppGroups"
	
	if let groupDefaults = groupDefaults {
		if !groupDefaults.boolForKey(didMigrateToAppGroups) {
			for key in userDefaults.dictionaryRepresentation().keys {
				groupDefaults.setObject(userDefaults.dictionaryRepresentation()[key], forKey: key)
			}
			groupDefaults.setBool(true, forKey: didMigrateToAppGroups)
			groupDefaults.synchronize()
			print("Successfully migrated defaults")
		} else {
			print("No need to migrate defaults")
		}
	} else {
		print("Unable to create NSUserDefaults with given app group")
	}
	
}

Gist

Comments closed