Skip to content →

diego.org Posts

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/

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);

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

Errors while installing APK from Android shell

I ran into 2 error while trying to install an APK from the Android shell. Note the apk is on the Android filesystem and I am installing it from the shell, not using adb.

The first error I got was: INSTALL_FAILED_INVALID_URI

$ pm install myApp.apk
	pkg: myApp.apk
Failure [INSTALL_FAILED_INVALID_URI]

This is because you need to give the full path to the apk, like:

$ pm install /sdcard/myApp.apk

The next error I got was INSTALL_FAILED_UID_CHANGED:

$ pm install /sdcard/myApp.apk
	pkg: /sdcard/myApp.apk
Failure [INSTALL_FAILED_UID_CHANGED]

I was installing over an existing app. The first thing I tried was to uninstall the app, but that didn’t work. I found that removing the data directory for the app solved my problem:

$ rm -rf /data/data/com.my.app.myApp/
Comments closed

Cocoapods – Generated duplicate UUIDs

I recently added another target to my Podfile to support tvOS. Here is an example of what the Podfile looks like:

source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!

target 'AppiOS' do
        platform :ios, '9.0'
        pod 'AFNetworking', '3.0.0-beta.1'
end

target 'AppTV' do
    platform :tvos, '9.0'
    pod 'AFNetworking', '3.0.0-beta.1'
end

I got this really long error complaining of duplicate UUIDS. Here is a shortened version:

[!] [Xcodeproj] Generated duplicate UUIDs:

PBXFileReference -- 
.... /Products/AFNetworking.framework

From what I understand, this deterministic UUIDs is a harmless warning and can be disabled by running the following command in the terminal. Then run pod install again.

$ export COCOAPODS_DISABLE_DETERMINISTIC_UUIDS=YES
Comments closed

Downgrading Cocoapods

I recently had some issues with a pre-release version of Cocoapods. To fix it, the suggestion was to downgrade Cocoapods to a previous version. It wasn’t obvious how to do that, but this is what I learned.

First you can figure out which version of Cocoapods you are on with the command:

pod --version

You can also see all the version of Cocoapods you have installed with this command:

sudo gem list cocoapods

Next uninstall Cocoapods. If you have multiple version, you will have the choice of uninstalling all or a specific version.

sudo gem uninstall cocoapods

Finally you can install the specific version with this command:

sudo gem install cocoapods -v 0.39.0.beta.3
Comments closed