I'm porting an app from Eclipse to Android Studio and am running into verify errors when trying to run the app on emulators with API less than 17. I'd appreciate any guidance on how to deal with this. Here's what shows up in logcat on an API 8 emulator:
12-27 01:48:27.189 431-431/com.zigzagworld.icjl.tanachbible W/dalvikvm: VFY: register1 v10 type 12, wanted 10
12-27 01:48:27.189 431-431/com.zigzagworld.icjl.tanachbible W/dalvikvm: VFY: rejecting opcode 0x70 at 0x005e
12-27 01:48:27.189 431-431/com.zigzagworld.icjl.tanachbible W/dalvikvm: VFY: rejected Lcom/zigzagworld/fonts/GlyphMetrics;.<init> (SSS[S)V
12-27 01:48:27.189 431-431/com.zigzagworld.icjl.tanachbible W/dalvikvm: Verifier rejected class Lcom/zigzagworld/fonts/GlyphMetrics;
This is followed immediately (no surprise) by the app crashing with a java.lang.VerifyError
. The same .apk file will run just fine on API level 17 and above. There are different code paths at API 17 and above, but the GlyphMetrics
class is used at some point regardless of API level. (If different code paths can make a difference as to whether a class generates a verify error when it is loaded, someone please let me know!)
The GlyphMetrics
class is a very simple container for some metric information concerning a home-brew bitmap font we use in the app:
package com.zigzagworld.fonts;
import static com.zigzagworld.fonts.Diacritics.LOWER_DIACRITIC;
import static com.zigzagworld.fonts.Diacritics.UPPER_DIACRITIC;
/**
* Represents the layout metrics for a glyph.
*
* @author Ted Hopp
*/
public final class GlyphMetrics {
public static final short[] EMPTY_EXCLUSION = new short[0];
public static final short[][] EMPTY_EXCLUSIONS = { EMPTY_EXCLUSION, EMPTY_EXCLUSION };
/** The width of the glyph image, in pixels. */
public short width;
/** The height of the glyph image, in pixels. */
public short height;
/**
* The distance in pixels between the top of the glyph image and the
* baseline of the line. A positive value means that the top of the glyph
* should be above the baseline of the line; a negative value means that the
* top of the glyph should be below the baseline of the line.
*/
public short baseline;
/**
* The upper and lower axes for placement of diacriticals. Each axis is the
* distance from the left of the glyph image at which diacriticals should be
* centered. (The formatting algorithm for the font may move diacriticals
* from this position to avoid interference between glyphs.)
*/
public short[] axes;
/**
* The upper and lower exclusion zone arrays. If there are <i>n</i> upper
* (say) zones, the upper array has length length 2*<i>n</i>. The array has
* the left edge of the first zone, the right edge of the first zone, the
* left edge of the second zone, etc. The lower zone data are organized in
* the same way.
*/
public short[][] zones;
public GlyphMetrics(short width, short height, short baseline, short[] layoutData) {
this.width = width;
this.height = height;
this.baseline = baseline;
axes = new short[2];
width >>= 1; // for the rest of this, we need the half-width
if (layoutData == null || layoutData.length == 0) {
axes[UPPER_DIACRITIC] = axes[LOWER_DIACRITIC] = width;
zones = EMPTY_EXCLUSIONS;
} else {
axes[UPPER_DIACRITIC] = layoutData[0];
if (layoutData.length < 2) {
axes[LOWER_DIACRITIC] = width;
} else {
axes[LOWER_DIACRITIC] = layoutData[1];
}
if (layoutData.length < 5) {
zones = EMPTY_EXCLUSIONS;
} else {
int nUpper = layoutData[2] << 1;
zones = new short[2][];
zones[UPPER_DIACRITIC] = new short[nUpper];
System.arraycopy(layoutData, 3, zones[UPPER_DIACRITIC], 0, nUpper);
int lowerStart = 3 + nUpper;
if (layoutData.length < 2 + lowerStart) {
zones[LOWER_DIACRITIC] = EMPTY_EXCLUSION;
} else {
int nLower = layoutData[lowerStart++] << 1;
zones[LOWER_DIACRITIC] = new short[nLower];
System.arraycopy(layoutData, lowerStart, zones[LOWER_DIACRITIC], 0, nLower);
}
}
}
}
}
(The imports UPPER_DIACRITIC
and LOWER_DIACRITIC
are the constants 0 and 1, respectively.)
I'm building this using Android Studio 2.0 Preview 4 with Gradle plugin com.android.tools.build:gradle:2.0.0-alpha3
and JDK 1.7.0_80. Here's the build.gradle
file for the .apk module:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion '23.0.2'
defaultConfig {
applicationId "com.zigzagworld.icjl.tanachbible"
minSdkVersion 8
targetSdkVersion 23
versionCode 10800310
versionName "3.1.0"
manifestPlaceholders = [
appName: "App",
v8TOCActivityName: "BaseTOCActivity",
v8PurchaseActivityName: "PurchaseActivity",
v17TOCActivityName: "TOCActivity",
v17PurchaseActivityName: "PurchaseActivity",
]
}
signingConfigs {
// redacted for this post
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//noinspection GroovyAssignabilityCheck
signingConfig // redacted
}
}
flavorDimensions "market"
productFlavors {
google {
dimension "market"
manifestPlaceholders = [
appName: "App_Google",
v8TOCActivityName: "TOCActivity_Google",
v8PurchaseActivityName: "GooglePurchaseActivity",
v17TOCActivityName: "TOCActivity_Google",
v17PurchaseActivityName: "GooglePurchaseActivity"
]
}
amazon {
dimension "market"
manifestPlaceholders = [
appName: "App_Amazon",
v8TOCActivityName: "BaseTOCActivity",
v8PurchaseActivityName: "PurchaseActivity",
v17TOCActivityName: "TOCActivity",
v17PurchaseActivityName: "PurchaseActivity"
]
}
sideLoad {
dimension "market"
manifestPlaceholders = [
appName: "App_Unlicensed",
v8TOCActivityName: "BaseTOCActivity",
v8PurchaseActivityName: "PurchaseActivity",
v17TOCActivityName: "TOCActivity",
v17PurchaseActivityName: "PurchaseActivity"
]
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:support-annotations:23.1.1'
compile project(':Tanach Data')
googleCompile project(':Google Vending')
amazonCompile project(':Amazon Vending')
}
The problem shows up with the debug build type, so ProGuard isn't in the picture at this point.