I am facing with a wierd situation where the class is definitely on the classpath of my android app but I keep getting NoClassDefFoundError exceptions.
I have checked that the class indeed exists through this code snippet:
try{
Field dexField = PathClassLoader.class.getDeclaredField("mDexs");
dexField.setAccessible(true);
PathClassLoader classLoader =
(PathClassLoader)Thread.currentThread().getContextClassLoader();
Log.d("OUT", "Class loader" + classLoader.getClass().getName());
DexFile[] dexs = (DexFile[]) dexField.get(classLoader);
Log.d("OUT", "Enumerating");
for (DexFile dex : dexs) {
Enumeration<String> entries = dex.entries();
while (entries.hasMoreElements()) {
// (3) Each entry is a class name, like "foo.bar.MyClass"
String entry = entries.nextElement();
Log.d("OUT", "Entry: " + entry);
}
}
}catch(Throwable e){
Log.e("OUT", e.getMessage(), e);
}
// Here I reference to the problematic class
When running the app on a device the log does print the class name, and throws the NoClassDefFoundError error upon accessing to it.
I'm lost here.
Any advice? I'd be very grateful. Thanks.
You need to understand that, at least in canonical Java, "NoClassDefFoundError" does not mean that the named .class file could not be found in the classpath. Rather, after it was located some problem prevented the class from being loaded.
Two common reasons for this are a naming problem (the class in the wrong location in the classpath structure, relative to its internally declared package name, or simply misnamed), or a problem loading some other class that's needed to perform validation of the named class. Occasionally the problem is due to an exception in the static initializer of the class.
Related
So I have been using the YouTube API successfully for the past few months in Android Studio. I went to update my app and as of today the app keeps crashing when it is trying to initialize the YouTube builder. Has anyone else experienced this problem?
mYoutubeDataApi = new YouTube.Builder(mTransport, mJsonFactory, null)
.setApplicationName(getResources().getString(R.string.app_name))
.build();
The app crashes with the following output:
2019-12-09 01:38:06.443 17937-17937/ E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.ExceptionInInitializerError
at com.google.api.services.youtube.YouTube.<clinit>(YouTube.java:44)
at com.google.api.services.youtube.YouTube$Builder.build(YouTube.java:16644)
Line 44 in the YouTube.java file is:
public class YouTube extends com.google.api.client.googleapis.services.json.AbstractGoogleJsonClient {
// Note: Leave this static initializer at the top of the file.
static {
com.google.api.client.util.Preconditions.checkState(
com.google.api.client.googleapis.GoogleUtils.MAJOR_VERSION == 1 &&
com.google.api.client.googleapis.GoogleUtils.MINOR_VERSION >= 15,
"You are currently running with version %s of google-api-client. " +
"You need at least version 1.15 of google-api-client to run version " +
"1.30.1 of the YouTube Data API library.", com.google.api.client.googleapis.GoogleUtils.VERSION);
}
In 1.30.6, they added this: https://github.com/googleapis/google-api-java-client/pull/1419
To fix, edit your build.gradle back down to 1.30.5
dependencies {
implementation ('com.google.api-client:google-api-client:1.30.5')
implementation ('com.google.api-client:google-api-client-android:1.30.5')
}
If there's a better solution, I'd like to hear it!
To further explain why that change in 1.30.6 causes the crash, here's some more info.
Specifically, the issue is coming from this file: https://github.com/googleapis/google-api-java-client/blob/master/google-api-client/src/main/java/com/google/api/client/googleapis/GoogleUtils.java
Caused by: java.lang.IllegalStateException: No successful match so far
at java.util.regex.Matcher.ensureMatch(Matcher.java:1116)
at java.util.regex.Matcher.group(Matcher.java:382)
at com.google.api.client.googleapis.GoogleUtils.<clinit>(Unknown Source:26)
Here is the relevant code
public static final String VERSION = getVersion();
static final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(-SNAPSHOT)?");
static {
Matcher versionMatcher = VERSION_PATTERN.matcher(VERSION);
versionMatcher.find();
MAJOR_VERSION = Integer.parseInt(versionMatcher.group(1));
MINOR_VERSION = Integer.parseInt(versionMatcher.group(2));
BUGFIX_VERSION = Integer.parseInt(versionMatcher.group(3));
}
private static String getVersion() {
String version = GoogleUtils.class.getPackage().getImplementationVersion();
// in a non-packaged environment (local), there's no implementation version to read
if (version == null) {
// fall back to reading from a properties file - note this value is expected to be cached
try (InputStream inputStream =
GoogleUtils.class.getResourceAsStream("google-api-client.properties")) {
if (inputStream != null) {
Properties properties = new Properties();
properties.load(inputStream);
version = properties.getProperty("google-api-client.version");
}
} catch (IOException e) {
// ignore
}
}
return version;
}
Presumably, getVersion is returning null, although I can't say why. Seeing as how this recently happened for me 2-3 days ago also, something we updated must be conflicting.
This bug is fixed in com.google.api-client:google-api-client:1.30.7. Upgrading to that version or later will fix it.
In the latest version, they have added the library proguard file, which keeps the the GoogleUtils.java and hence keeps the google-api-client.properties which gets generated in build time.
Initially they used to update the string literal for version name for each release hence that time parsing of version name done in GoogleUtils.java was crash free.
But later on they shifted to parsing the version from google-api-client.properties at GoogleUtils.java which started giving error as proguard started removing the generated google-api-client.properties file.
Later on after release, 1.30.9 at this commit id the started using the embedded proguard rule to keep the GoogleUtils.java file
They actually fixed the issue at release, 1.30.8 at the commit, 1.30.9 release just does the same fix in more android recommended way.
Although the final adopted version uses GoogleUtils.class.getResourceAsStream("google-api-client.properties") which is Java api and returns the InputStream to read the google-api-client.properties file. Since these stream may not work perfectly in some devices they still crash but with lesser frequency(as we still see the crashes with the fixed present in the release 1.30.9).
Created an issue to track this
I see a crash whenever my android app initializes a kotlin class. From the stack trace, I see it's from the static initializer of the BuiltInsLoader.Companion object:
kotlin.collections.CollectionsKt___CollectionsKt.first
(CollectionsKt___CollectionsKt.java:166)
kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader$Companion.
(BuiltInsLoader.java:38)
kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader.
(BuiltInsLoader.java)
kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns.createBuiltInsModule
(KotlinBuiltIns.java:150)
kotlin.reflect.jvm.internal.impl.platform.JvmBuiltIns.
(JvmBuiltIns.java:56)
kotlin.reflect.jvm.internal.impl.platform.JvmBuiltIns.
(JvmBuiltIns.java:31)
kotlin.reflect.jvm.internal.components.RuntimeModuleData$Companion.create
(RuntimeModuleData.java:54)
kotlin.reflect.jvm.internal.KDeclarationContainerImpl$Data$moduleData$2.invoke
(KDeclarationContainerImpl.java:35)
kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke
(ReflectProperties.java:93)
kotlin.reflect.jvm.internal.ReflectProperties$Val.getModuleData
(ReflectProperties.java:32)
kotlin.reflect.jvm.internal.KClassImpl$Data$descriptor$2.invoke
(KClassImpl.java:46)
kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke
(ReflectProperties.java:93)
kotlin.reflect.jvm.internal.ReflectProperties$Val.getDescriptor
(ReflectProperties.java:32)
kotlin.reflect.jvm.internal.KClassImpl.getDescriptor
(KClassImpl.java:172)
kotlin.reflect.jvm.internal.KClassImpl.getConstructorDescriptors
(KClassImpl.java:186)
kotlin.reflect.jvm.internal.KClassImpl$Data$constructors$2.invoke
(KClassImpl.java:90)
kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke
(ReflectProperties.java:93)
kotlin.reflect.jvm.internal.ReflectProperties$Val.create
(ReflectProperties.java:32)
The decompiled static block looks like this:
BuiltInsLoader.Companion var0 = new BuiltInsLoader.Companion();
$$INSTANCE = var0;
ServiceLoader var10000 = ServiceLoader.load(BuiltInsLoader.class, BuiltInsLoader.class.getClassLoader());
Intrinsics.checkExpressionValueIsNotNull(var10000, "ServiceLoader.load(Built…::class.java.classLoader)");
Object var1 = CollectionsKt.first((Iterable)var10000);
Has anyone else experienced this crash? If so, how do you fix this initialization error?
This exception can occur if a certain resource file, needed for kotlin-reflect to work correctly, is missing at runtime. The file is located at META-INF/services/kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader. Please verify that no tools remove it during the build and it's present in the final application.
The relevant issue in the Kotlin tracker: https://youtrack.jetbrains.com/issue/KT-20575
Maybe:
packagingOptions {
exclude 'META-INF/services/kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader'
}
Might help
I'm trying to introduce the ACRA lib in my library project. When I set up the String for the toast, I get a "Attribute value must be a constant" error. Please see attached screen-shots
and the R.string.crash_toast_text:
Please note that these lines of code are from here
https://github.com/ACRA/acra/wiki/AdvancedUsage#toast-notification
Based on CommonsWare 18 answer, I made it work. Here is a sample code if anyone gets stuck in the same situation:
final ACRAConfiguration config = ACRA.getNewDefaultConfig(this);
try {
config.setMode(ReportingInteractionMode.TOAST);
} catch (ACRAConfigurationException e) {
e.printStackTrace();
}
config.setResToastText(R.string.crash_toast_text);
ACRA.init(this, config);
i cant figure out why the following happens:
I am running an embedded apache felix from a small android application. I programmatically install 2 bundles after starting the framework, but both never enter the "resolved" state. Thereby the Bundle "MyBundle1" imports "MyBundle2".
This is what Logcat tells me:
05-17 20:21:56.514: ERROR/MainActivity(384): org.osgi.framework.BundleException:
Unresolved constraint in bundle de.xy.MyBundle1 [1]: Unable to resolve 1.11: missing
requirement [1.11] package; (package=de.xy.MyBundle2) [caused by: Unable to resolve 2.0:
missing requirement [2.0] package; (&(package=org.osgi.framework)(version>=1.5.0))]
I totally understand what the error-message says (well...org.osgi.framework in version 1.5+ cant be resolved) but i cant figure out why this happens. Why cant the framework resolve "himself"?! I tried to run the same felix.jar as standalone with the adb shell , and both bundles work. Ofcourse, the felix.jar is up to date (3.2)
Thanks for your advice!
Daniel
FelixSetup
m_configMap = new StringMap(false);
try {
m_cache = File.createTempFile("felix-cache", null);
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
m_cache.delete();
boolean mkdirs = m_cache.mkdirs(); // works (=true)
m_activator = new HostActivator(); // implements BundleActivator
List list = new ArrayList();
list.add(m_activator);
m_configMap.put(FelixConstants.LOG_LEVEL_PROP, "1");
m_configMap.put(BundleCache.CACHE_ROOTDIR_PROP, ".");
m_configMap.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, list);
m_configMap.put(FelixConstants.FRAMEWORK_STORAGE, m_cache.getAbsolutePath());
m_felix = new Felix(m_configMap);
try {
m_felix.start();
} catch (BundleException ex) {
Logger.getLogger(MainActivity.class.getName()).log(Level.SEVERE, null, ex);
}
I dont know if it has something to do with the previous problems:
05-18 08:52:59.149: VERBOSE/out(363): Problem creating boot delegation class loader: java.lang.reflect.InvocationTargetException
05-18 08:52:59.209: VERBOSE/out(363): ERROR: Error parsing system bundle export statement: (java.lang.IllegalArgumentException:A header cannot be an empty string.)
05-18 08:52:59.209: VERBOSE/out(363): java.lang.IllegalArgumentException: A header cannot be an empty string.
I install and start the bundles with
myBundle1= bundleContext.installBundle("file:/data/felix/MyBundle1.jar");
myBundle2= bundleContext.installBundle("file:/data/felix/MyBundle2.jar");
myBundle1.start();
they were previously dx'ed and moved to /data/felix with adb push.
The same code I used in the android-application also works inside a regular java console-app.
The way you build up the framework looks okay to me. You could consider
replacing the FRAMEWORK_SYSTEMPACKAGES by a list that is specific for Android, if your bundles will e.g. be using Activities), or
not using a temp file, but point to some directory you know exists.
We have used 3.0.1 in the past successfully, and I do have the idea that the error message you posted has something to do with it. You could try that version of Felix, and if that works, you may have found a regression in Felix, which you can then report to users#felix.apache.org .
Today I tried including the apache.commons.codec package in my Android application and couldn't get it running. Android could not find method ord.apache.commons.codec.binary.* and output the following errors in DDMS
01-12 08:41:48.161: ERROR/dalvikvm(457): Could not find method org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString, referenced from method com.dqminh.app.util.Util.sendRequest
01-12 08:41:48.161: WARN/dalvikvm(457): VFY: unable to resolve static method 10146: Lorg/apache/commons/codec/binary/Base64;.encodeBase64URLSafeString ([B)Ljava/lang/String;
01-12 08:41:48.161: WARN/dalvikvm(457): VFY: rejecting opcode 0x71 at 0x0004
Any clue on how to solve this problem ? Thanks a lot.
I had a similar problem while using android with an OAuth library I'm developing.
I also got from android that, although I had included apache.commons.codec in the classpath, a particular method (encodeBase64String) was not found.
Checking the javadocs, both methods claim to be 1.4 and greater only, so my guess is that android already includes an older version of commons.codec where these methods are indeed undefined.
My solution was to use an older method, like this:
String encodedString = new String(Base64.encodeBase64('string to encode'));
The method you want to use is different since it replaces + and / with url-safe values - and _. So you probably might use something like:
String encodedString = new String(Base64.encodeBase64('string to encode'));
String safeString = encodedString.replace('+','-').replace('/','_');
You don't have to use apache commons, on android you can use android.util.Base64 instead.
I experienced the exact same problem. So i started browsing the android source code, and as it turns out Pablo Fernandez's guess about Android having an implementation of org.apache.commons.code.binary is correct. However, its version 1.2 of the apache commons, not version 1.4 or even 1.5.
You can see for your self in the android source.
as a note this is question is a duplicate of this post
You can use the following function:
private static String encodeBase64URLSafeString(byte[] binaryData) {
return android.util.Base64.encodeToString(binaryData, Base64.URL_SAFE);
}
source + listing of other possible flags: http://developer.android.com/reference/android/util/Base64.html
My solution to the same problem was to rename the problematic class org.apache.commons.codec.binary.Base64.java into org.apache.commons.codec.binary.ApacheBase64.java. I did it using Eclipse refactor-rename.
That way, the latest and greatest apache solution is preserved and used, and there is no chance for accidental problem recurrence when my app is eventually being lifted from android 1.6 lowest denominator.
Note I had the entire apache commons source tree already set as separate Eclipse java project, next to my Android project. My Android project used many of Apache Commons classes, but failed on Base64 because of above described problems...
You could simply copy this code bit from the apache library (it is pretty isolated)
http://www.java2s.com/Open-Source/Android/Blog-Twitter/twitspeak/org/apache/commons/codec/binary/Base64.java.htm
Edit:
Updated link from the Wayback Machine as the original is gone:
http://web.archive.org/web/20130610025148/http://www.java2s.com/Open-Source/Android/Blog-Twitter/twitspeak/org/apache/commons/codec/binary/Base64.java.htm
Please note that this answer was made by Dylan Watson in the comments above:
Be aware that you need to use Base64.encode("foobar".getBytes(),
Base64.Base64.NO_WRAP); to get exactly the same result as the apache
commons library. See: stackoverflow.com/questions/17912119
This answer was the only which worked after hours of trying to communicate my android app with a java "desktop" app.
So here is some source code, maybe it will help others:
Code from the desktop applet:
private static String convertToBase64(String s) {
byte[] bytes = new byte[0];
try {
bytes = (s.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
return DatatypeConverter.printBase64Binary(bytes);
}
This snippet is used in the android app:
public static String convertToBase64(String password) {
byte[] bPwd = new byte[0];
try {
bPwd = (password.getBytes("UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
try {
password = new String(Base64.encode(bPwd, Base64.NO_WRAP), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return password;
}
You can simply import the following library under Gradle dependency
dependencies {
implementation "commons-codec:commons-codec:1.11"
}
It will work
did you include apache commons project lib,like
org.apache.commons:commons-compress
org.apache.commons:commons-email
org.apache.commons:commons-io
org.apache.commons:commons-lang3
org.apache.commons:commons-parent
org.apache.commons:commons-pool2
the commons-codec 's GAV is
commons-codec:commons-codec
but it's package name is
org.apache.commons.codec
this package name will be conflict with apache commons project libs,try to change the package name of commons-codec,then generate it as a jar or import the source code had changed the package name;
Knowing that this is an old question, but I faced this problem recently when compiling for API Level 23, and found another solution for the problem: use guava project.
// Encoding
String encodedString = BaseEncoding.base64().encode(text.getBytes(UTF_8));
System.out.println("encodedString: " + encodedString);
// Decoding
byte[] decodedString = BaseEncoding.base64().decode(encodedString);
System.out.println("decodedString: " + new String(decodedString, UTF_8));
The guava library (18.0) was the version that I've used, and the change was smooth. The code works as expected.
Solution found in here: https://memorynotfound.com/encode-decode-base64-string-using-native-java/
This works for me:
import org.apache.commons.codec.binary.Base64;
/**
* This is used to get the base64 from the bytes
*
* #param rawBytes the raw bytes
* #return the base64 encoded string
*/
public static String getBase64String(byte[] rawBytes) {
String base64Str = "";
if (rawBytes!= null) {
base64Str= new String(Base64.encodeBase64(rawBytes));
}
return base64Str;
}
public static byte[] getBase64DecodedString(String base64EncodedStr) {
byte[] base64Bytes = Base64.decodeBase64(base64EncodedStr.getBytes());
return bitmap;
}