Jake Wharton mentioned this library in a recent talk and it looks like a great way to avoid a load of boilerplate so I gave it a go. But without any success.
https://github.com/SimonVT/schematic
Below is the definition of the content provider with the annotation attached and the manifest provider element. The issue is that Android Studio does not like the provider definition because the content provider class does not extend ContentProvider.
Caused by: java.lang.ClassCastException: com.myapp.SchematicContentProvider
cannot be cast to android.content.ContentProvider
What am I missing? It could be related to android-apt which I am not using (Schematic recommends it but does not seem to require it) - when I try using android-apt I get a VerifyError so had to remove it from the build.
AndroidManifest.xml
<provider
android:name="com.myapp.SchematicContentProvider"
android:authorities="com.myapp.provider"
android:exported="false" />
And the class definition:
import net.simonvt.schematic.annotation.ContentProvider;
import net.simonvt.schematic.annotation.ContentUri;
import net.simonvt.schematic.annotation.TableEndpoint;
#ContentProvider(authority = SchematicContentProvider.AUTHORITY, database = SchematicDatabase.class)
public class SchematicContentProvider {
public static final String AUTHORITY = "com.myapp.provider";
interface Path {
String ROUTES = "routes";
}
#TableEndpoint(table = SchematicDatabase.ROUTES) public static class Routes {
#ContentUri(path = Path.ROUTES, type = "vnd.android.cursor.dir/list", defaultSort = SchematicRouteColumns.TITLE + " ASC")
public static final Uri ROUTES = Uri.parse("content://" + AUTHORITY + "/" + Path.ROUTES );
}
}
I've looked through the Schematic sample app (the code snippets in the readme are partial) but I can't see what I've missed. I'm not sure how to confirm that the code generation is working, how do I check? I looked under build but I only see BuildConfig under the Schematic package name.
It's a shame it's not working for me, it has great potential.
You aren't declaring the right ContentProvider.
You have to declare the generated one in the Manifest.
I should like this :
<provider
android:name=".yourOptionalPackage.generated.SchematicContentProvider"
android:authorities="com.myapp.provider"
android:exported="false" />
If your IDE (Android Studio/IntelliJ) shows red warning, just click on the Make Project button to generate the code.
If it's still not working, include apt-libs in your project (worth it), and to save even more time, use this awesome library also based on apt-libs ;)
Let me know in the comments if I solved your problem or not, and if you need help configuring your gradle file.
You receive this error because com.myapp.SchematicContentProvider is your class with annotations and isn't a generated ContentProvider (which will have the same name).
Louis Cognault provided a correct answer, but it worth to mention that Schematic has a special parameter packageName for #ContentProvider and #Database annotations. packageName defines where generated classes will be placed. It let's you to clarify creation of AndroidManifest.xml.
Provider definition class:
#ContentProvider(
authority = SchematicContentProvider.AUTHORITY,
database = SchematicDatabase.class,
packageName = "com.myapp.providerpackage")
public class SchematicContentProvider {
...
}
Database definition class:
#Database(
version = SchematicDatabase.VERSION,
packageName = "com.myapp.providerpackage"
)
public class SchematicDatabase{
public static final int VERSION = 1;
...
}
AndroidManifest.xml:
<provider
android:name="com.myapp.providerpackage.SchematicContentProvider"
android:authorities="com.myapp.provider"
android:exported="false" />
Related
Using Mixpanel I am able to send out notifications directly from their control panel, however currently it uses a weirdly cropped version of the launcher icon as the notification icon.
I have seen some answers for customising the icon using a customised BroadcastReceiver, but I can't seem to get it to working in this case. Has anyone successfully managed to change the notification icon when sending directly from Mixpanel?
Thanks.
Actually, there is a way to set a custom icon for android push notifications without writing your own custom broadcast receiver. Recent versions of the Mixpanel android library understand a "mp_icnm" parameter that can refer to the name of a resource in your application. The library itself is also packaged with a set of predefined icons you can use. The quick way is to put the following snippet into the "custom data" field
{"mp_icnm":"com_mixpanel_android_ic_megaphone"}
I've attached a screenshot of the Mixpanel app with a picture of the text field. You'll want to be sure that this data is entered in "Android" preview mode when you enter your data, as shown in the illustration.
You can use any drawable resource in your app for an icon- the whole list of prepackaged notification icons can be found here in the Mixpanel library, and their resource names are listed below.
com_mixpanel_android_ic_bell
com_mixpanel_android_ic_clipboard_checkmark
com_mixpanel_android_ic_coin
com_mixpanel_android_ic_flag
com_mixpanel_android_ic_gear
com_mixpanel_android_ic_inbox
com_mixpanel_android_ic_megaphone
com_mixpanel_android_ic_phone
com_mixpanel_android_ic_rocket
com_mixpanel_android_ic_sale_tag
com_mixpanel_android_ic_sync
com_mixpanel_android_ic_trophy
com_mixpanel_android_ic_vip
com_mixpanel_android_ic_warning
Be aware that the Mixpanel resources might be removed by your proguard configuration, so you'll want to be sure that you haven't stripped them if you want to use them.
To answer one aspect of #user1544797's question and in addition to #user128536's answer, you may want to let your app be responsible of configuring your notification icon and not rely on the Mixpanel preview mode. To do so, you must intercept Mixpanel broadcast by creating your own BroadcastReceiver that extends Mixpanel's GCMReceiver :
public class MixpanelGCMReceiver extends GCMReceiver {
#Override
public void onReceive(Context context, Intent intent) {
intent.putExtra("mp_icnm", "<your_icon_name>");
super.onReceive(context, intent);
}
}
Then declare your BroadcastReceiver in your AndroidManifest.xml file :
<receiver
android:name="<your_package_name>.MixpanelGCMReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
Finally, #user128536 is right about warning you that Proguard is messing up with your notification icon if not managed properly (and unfortunately Mixpanel does not document how your app should handle this case). However, in addition to Proguard, there is another issue that you may need to tackle when you are using an applicationId that differs from your packageName (usually while using product flavors). In the ResourceReader class from Mixpanel SDK, you can see this comment :
MPLog.w(LOGTAG, "Can't load names for Android view ids from '" + localClassName + "', ids by name will not be available in the events editor.");
MPLog.i(LOGTAG, "You may be missing a Resources class for your package due to your proguard configuration, " +
"or you may be using an applicationId in your build that isn't the same as the package declared in your AndroidManifest.xml file.\n" +
"If you're using proguard, you can fix this issue by adding the following to your proguard configuration:\n\n" +
"-keep class **.R$* {\n" +
" <fields>;\n" +
"}\n\n" +
"If you're not using proguard, or if your proguard configuration already contains the directive above, " +
"you can add the following to your AndroidManifest.xml file to explicitly point the Mixpanel library to " +
"the appropriate library for your resources class:\n\n" +
"<meta-data android:name=\"com.mixpanel.android.MPConfig.ResourcePackageName\" android:value=\"YOUR_PACKAGE_NAME\" />\n\n" +
"where YOUR_PACKAGE_NAME is the same string you use for the \"package\" attribute in your <manifest> tag."
);
As indicated in the above comment, if you find yourself in this situation, just add in your AndroidManifest.xml file the following block :
<meta-data
android:name="com.mixpanel.android.MPConfig.ResourcePackageName"
android:value="<your_package_name>" />
That's it, you should be done by now ;)
Additionally you can add small icon witch will be shown in status bar.
"mp_icnm_w": "your_small_icon_id"
It should be white with transparent bg.
I'm putting this answer for all the people who are unable to figure out the perfect solution even after reading all the previous answers. I'll sum down all the key points which are required to show your app's icon when you receive the Mixpanel push.
If you're using ProGuard (in my case which I was), you need to put below settings in your Proguard Rule file.
keepclassmembers class **.R$* {
public static <fields>;
}
Add below code in your Manifest.xml file.
<meta-data
android:name="com.mixpanel.android.MPConfig.ResourcePackageName"
android:value="YOUR_PACKAGE_NAME" />
This is the package name (package="YOUR_PACKAGE_NAME") declared in your Application's manifest file (YOUR_PACKAGE_NAME is for example. Replace it with your actual Package name value). Don't mix it up with Application Id. It will not work if you put your Application Id here.
Point 1 & 2 is also mentioned inside the ResourceReader class as mentioned in one of the above answer.
MPLog.w(LOGTAG, "Can't load names for Android view ids from '" + localClassName + "', ids by name will not be available in the events editor.");
MPLog.i(LOGTAG, "You may be missing a Resources class for your package due to your proguard configuration, " +
"or you may be using an applicationId in your build that isn't the same as the package declared in your AndroidManifest.xml file.\n" +
"If you're using proguard, you can fix this issue by adding the following to your proguard configuration:\n\n" +
"-keep class **.R$* {\n" +
" <fields>;\n" +
"}\n\n" +
"If you're not using proguard, or if your proguard configuration already contains the directive above, " +
"you can add the following to your AndroidManifest.xml file to explicitly point the Mixpanel library to " +
"the appropriate library for your resources class:\n\n" +
"<meta-data android:name=\"com.mixpanel.android.MPConfig.ResourcePackageName\" android:value=\"YOUR_PACKAGE_NAME\" />\n\n" +
"where YOUR_PACKAGE_NAME is the same string you use for the \"package\" attribute in your <manifest> tag."
);
If you're already using a FCMPushReceiver and you want to integrate Mixpanel notification support, please follow the guidelines mentioned here.
Irrespective of whether you're using a MixpanelFCMMessagingService or FirebaseMessagingService, you need to put below code inside onMessageReceived() section.
/* drawable_name is just the Drawable Name like if you app logo is app_icon,
use "app_icon" instead of "R.drawable.app_icon" */
if (TextUtils.isEmpty(intent.getStringExtra("mp_icnm"))) {
intent.putExtra("mp_icnm", "drawable_name"); // mp_icnm is used for the app icon
}
if (TextUtils.isEmpty(intent.getStringExtra("mp_icnm_l"))) {
intent.putExtra("mp_icnm_l", "drawable_name"); // mp_icnm_l is used for the large icon
}
if (TextUtils.isEmpty(intent.getStringExtra("mp_icnm_w"))) {
intent.putExtra("mp_icnm_w", "drawable_name"); // mp_icnm_w is used for the White icon
}
For more info on the parameters used by Mixpanel, you can check the parseIntent method of MixpanelPushNotification class.
In case of MixpanelFCMMessagingService, you can get the intent in the method parameter. For FirebaseMessagingService, you can get the intent by doing like below -
final Intent intent = remoteMessage.toIntent();
I'm attempting to follow the example tutorial at https://developers.google.com/eclipse/docs/endpoints-addentities and I'm stuck figuring out how to get the GameEndpoint.Builder class to generate within Eclipse.
After following this and generating the cloud endpoints as described, I have a GameEndpoint class created, but there is no GameEndpoint.Builder class. So obviously I have this error
GameEndpoint.Builder cannot be resolved to a type
I'm stumped at this point. How do I generate the GameEndpoint.Builder class within Eclipse, or what would prevent it?
Code
public class NewGameTask extends AsyncTask<Context, Integer, Long> {
protected Long doInBackground(Context... contexts) {
GameEndpoint.Builder endpointBuilder = new GameEndpoint.Builder(
AndroidHttp.newCompatibleTransport(), new JacksonFactory(),
new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
}
});
GameEndpoint endpoint = CloudEndpointUtils.updateBuilder(
endpointBuilder).build();
try {
Game game = new Game();
game.setStart(Calendar.getInstance());
Game result = endpoint.insertGame(game);
} catch (IOException e) {
e.printStackTrace();
}
return (long) 0;
}
}
I figured out my issue after watching this video from Google I/O 2013 which is using Android Studio, but it was the same thing as Eclipse mostly.
My mistake in following https://developers.google.com/eclipse/docs/endpoints-addentities was that you need to put your entity class into the MyApp-AppEngine project and NOT your MyApp project.
That was the source of confusion. In case it helps those in the future, here is a short breakdown of what I did.
Put the Entity class you want to add to App Engine into your MyApp-AppEngine project.
Right click your class and go to Google > Generate Cloud Endpoint Client Library
Right click your MyApp-AppEngine project and go to Google > Generate Cloud Enpoint Client Library
New references will be made in your MyApp project which you reference in your project for usage.
Note This answer is based on Android Studio, but am sure it's pretty much the same as Eclipse.
I also had this issue but later found the cause.Turns out I was importing the Endpoint class I generated instead of the endpoint Api package. Let me be clear.When you add the endpoint module to your project, you get the MyBean and MyEndpoint classes in the endpoint package. If you take a look at the guide to connecting your client to your backend, the EndpointsAsyncTask class uses:
private static MyApi myApiService = null;
Note how it uses MyApi instead of MyBean Now I was wondering where it got that from but I just have to take a look at my backend libraries:
The library marked 1 is the library first added to your project when you follow the guide previously mentioned. When I added a new class Student and autogenerated the cloud endpoint class, the second library was also added.
Long, boring story short; It is this library you should be importing and not the class.
import com.package-name.backend.studentApi.StudentApi;
and then using:
private static StudentApi myApiService = null;
...
StudentApi.Builder builder = new StudentApi.Builder(...)
instead of:
import com.package-name.backend.StudentEndpoint;
...
private static StudentEndpoint myApiService = null;
StudentEndpoint.Builder builder = new StudentEndpoint.Builder(...)
I got the same problem in Android Studio. I generated my Endpoint class from my entity java bean but when creating the AsyncTask, now way to get the Builder.
Actually (if I take a Game java bean like you) the Builder is not depending on the GameEndPoint but on the generated GameApi class.
In other words, I had to add these two imports in the AsyncTask class:
import com.examplepackage.backend.gameApi.GameApi;
import com.examplepackage.backend.gameApi.model.Game;
while the Game java bean that you wrote and the generated GameEndpoint are under package com.examplepackage.backend
I am using Log4j to log data in my android application. I have configured the log4j with the help of the following class, but the log files are not getting created.
console logging is enabled, maxfilesize and maxbackupsize are also good. please let me know what i am missing here.
public class ConfigureLog4J {
static LogConfigurator logConfigurator = new LogConfigurator();
private static final int maxFileSize = 1024 * 5; // 100KB
public static final int maxBackupSize = 2; // 2 backup files
public static final String LOG_FILE_NAME = "bitzer.log";
private static HashMap<Integer, Level> logLevelMap = new HashMap<Integer, Level>();
static {
logLevelMap.put(0, Level.OFF);
logLevelMap.put(1, Level.ERROR);
logLevelMap.put(2, Level.INFO);
logLevelMap.put(3, Level.WARN);
logLevelMap.put(4, Level.DEBUG);
logLevelMap.put(5, Level.ALL);
}
public static void startWithLogLevel(int logLevel) {
logConfigurator.setFileName(getLogFileName());
logConfigurator.setRootLevel(getLevelFromInt(logLevel));
logConfigurator.setUseFileAppender(true);
logConfigurator.setUseLogCatAppender(isConsoleLoggingEnabled());
logConfigurator.setMaxFileSize(getMaxFileSize());
logConfigurator.setMaxBackupSize(maxBackupSize);
// Set log level of a specific logger
// logConfigurator.setLevel("org.apache", Level.ERROR);
logConfigurator.setResetConfiguration(true);
logConfigurator.configure();
}
private static long getMaxFileSize() {
return CompanySettings.getInstance().getValueAsInteger(R.string.max_log_size);
}
private static boolean isConsoleLoggingEnabled() {
return CompanySettings.getInstance().getValueAsBoolean(R.string.consoleLoggingEnabled);
}
private static Level getLevelFromInt(int newLogLevel) {
return logLevelMap.get(newLogLevel);
}
public static String getLogsDirectory() {
if(AppData.getInstance().getContext()!=null)
{ String packageName = AppData.getInstance().getContext().getPackageName();
System.out.println("sundeep package name is not null and it's"+packageName);
return "data/data/" + packageName + "/logs/";
}
return null;
}
public static String getLogFileName() {
return getLogsDirectory() + LOG_FILE_NAME;
}
}
SLF4J Overview
I highly recommend you use SLF4J, which is log4j's "older brother" of sorts; the same developers who made log4j made SLF4J to address the shortcomings of log4j.
The difference is, whereas log4j is a full-fledged logging framework, SLF4J is a facade which you use directly in your Java code. The facade aspect allows you to plugin a concrete logging implementation — such as log4j, logback, Android's Log utility, etc. — at runtime.
It allows you to write code that can be used between different projects without having to go through your code and convert your logging statements to use the target project's logging framework. If you have several thousand lines of code which use log4j, but the target you're importing them into uses Apache Commons logging, you'll soon find yourself with a headache if you manually make the changes... even with the assistance of a capable IDE.
Using log4j in Android
There's a great Android library for logging to log4j — as well as many other logging frameworks as well — called android-logging-log4j. Check out the very excellent section on "Using log4j over slf4j", which is the route I take in my Android projects.
Examples from my own projects
Here are some examples from my own projects, such as my Awnry News & Weather app. (Yeah, shameless plug :P)
Required JARs on classpath
Basically these are the JARs I'll typically have in my project's classpath (version numbers vary as new releases come about, of course).
android-logging-log4j-1.0.3.jar
log4j-1.2.17.jar
slf4j-api-1.7.6.jar
slf4j-log4j12-1.7.6.jar
Instantiating a class's logger
And here's how I instantiate my general logger in each of my classes that require logging:
package com.awnry.android.naw;
...
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
public class NawApplication extends Application
{
private static final Logger log = LoggerFactory.getLogger(NawApplication.class);
As you can see, I'm only referencing SLF4J's Logger and LoggerFactory interfaces, even though the actual logging may eventually be accomplished using log4j or Android's Log.
That's the beauty of SLF4J's facade design: You aren't tied down to any specific logging implementation/framework; you can change your mind in the future without having to change a line of your code. If you're using log4j over SLF4J now, but in the future you want to use the Apache Commons Logging framework all you have to do is switch out the SLF4J-to-log4j bridge to a SLF4J-to-ACL bridge, and none of your Java code will be any wiser as it only calls SLF4J interfaces. The time-honored adage to code to an interface, not an implementation holds true once again, and SLF4J is a superb example of that.
Configuring the Android app's logging
In my Application.onCreate() method, I configure my logging like this:
#Override
public void onCreate()
{
...
String logFile = getFilesDir().getAbsolutePath() + File.separator + "logs" + File.separator + "debug.log";
log.info("Application log file: " + logFile);
LogConfigurator logConfigurator = new LogConfigurator(logFile, Level.TRACE);
logConfigurator.configure();
...
}
This part is actually optional, I believe. In my case I do this because I use the ACRA library to help catch unexpected program crashes and report the details back to me for debugging, so you might not need to define your android-logging-log4j's LogConfigurator as I do here.
Why you are using log4j.
There are efficient Log utility is available specially designed for android.
Use LogCat. Its very simple to use and standard way of putting log in your android app.
Could you guys please help me why I'm having this exception?
I extracted RequestFactory proxies and context interfaces into separate jar so I can use it both in GWT client and Android client (details are here)
Unfortunately RF throws an exception on the server in very first call. The exception is:
com.google.web.bindery.requestfactory.server.UnexpectedException: No RequestContext for operation LPZEK7DlYkoG1$NQ5MjHlmuRChk=
at com.google.web.bindery.requestfactory.server.ServiceLayerDecorator.die(ServiceLayerDecorator.java:216)
at com.google.web.bindery.requestfactory.server.ResolverServiceLayer.resolveRequestContext(ResolverServiceLayer.java:154)
Below is my factory interface. As you can see I had to replace Service annotations with ServiceName because I didn't want to compile all custom locators with Guice injections to jar that will go on mobile devices.
public interface AdminRequestFactory extends RequestFactory
{
// #Service(value = UserServiceDao.class, locator = InjectingServiceLocator.class)
#ServiceName(value = "com.blah.courierApp.server.dao.UserServiceDao", locator = "com.blah.courierApp.server.inject.InjectingServiceLocator")
public interface GaeUserServiceContext extends RequestContext
{
public Request<String> createLogoutURL(String destinationURL);
public Request<GaeUser> getCurrentUser();
}
// #Service(value = OrderDao.class, locator = InjectingServiceLocator.class)
#ServiceName(value = "com.blah.courierApp.server.dao.OrderDao", locator = "com.blah.courierApp.server.inject.InjectingServiceLocator")
public interface OrderRequestContext extends RequestContext
{
Request<List<OrderProxy>> listAll();
Request<Void> delete(Long id);
Request<Void> createOrder(OrderProxy order);
Request<OrderProxy> findOrderById(long id);
Request<Void> updateOrderState(long id, StateType newStateType);
}
GaeUserServiceContext contextUserService();
OrderRequestContext contextOrder();
}
When I compiled it RF Annotation Tool gave following warning:
Cannot fully validate context since domain type com.blah.courierApp.server.dao.UserServiceDao is not available.
You must run the ValidationTool as part of your server build process.
Add #SuppressWarnings("requestfactory") to dismiss.
So when the exception thrown under the debugger on the server I see that instance of com.google.web.bindery.requestfactory.vm.impl.Deobfuscator has empty operationData field which is being initialized by DeobfuscatorBuilder class that was generated by RequestFactory annotation tool.
So... I decompiled that class and found this:
public final class AdminRequestFactoryDeobfuscatorBuilder extends Deobfuscator.Builder
{
public AdminRequestFactoryDeobfuscatorBuilder()
{
withRawTypeToken("w1Qg$YHpDaNcHrR5HZ$23y518nA=", "com.google.web.bindery.requestfactory.shared.EntityProxy");
withRawTypeToken("8KVVbwaaAtl6KgQNlOTsLCp9TIU=", "com.google.web.bindery.requestfactory.shared.ValueProxy");
withRawTypeToken("FXHD5YU0TiUl3uBaepdkYaowx9k=", "com.google.web.bindery.requestfactory.shared.BaseProxy");
withRawTypeToken("5vjE9LUy$l0uvi4kMYpS3JA1WEE=", "com.blah.shared.model.GaeUser");
withRawTypeToken("8KVVbwaaAtl6KgQNlOTsLCp9TIU=", "com.google.web.bindery.requestfactory.shared.ValueProxy");
withRawTypeToken("5a7OV4PSV$1xemsooKLfEQ4g5yY=", "com.blah.shared.proxies.OrderProxy");
withRawTypeToken("neR_xIhE5oZsc0HbnkAMa8A88yw=", "com.blah.shared.proxies.OrderStateProxy");
withRawTypeToken("t6gMQWDROJnYvqYhNURV8pd$sn4=", "com.blah.shared.proxies.OrganizationProxy");
withRawTypeToken("1o45xgS$5bIkBKF4wlR8oMw_FSo=", "com.blah.shared.proxies.PersonProxy");
withRawTypeToken("FXHD5YU0TiUl3uBaepdkYaowx9k=", "com.google.web.bindery.requestfactory.shared.BaseProxy");
}
}
It didn't generated tokens for factory. Therefore there are no calls to Deobfuscator.Builder.withOperation because of which my server can't find context when calls comes from the client.
Questions are:
Why doesn't RequestFactory Annotation Tool generate tokens for factory (operations) ?
How can I fix it ?
Well, it was pretty tricky... But debugging in RF Annotation Tool helped :)
Turns out you have to have domain classes that you refer to in #ServiceName in classpath of RF Annotation Processor. It creates chicken-and-egg problem. You have to compile SharedClasses module to compile main module but you have to compile domain classes from main module to compile SharedClasses module.
Here is what I did:
Disabled RF annotation processing for SharedClasses module.
In RF annotation processor of main module I explicitly specified RF factory that has to be processed using parameter rootOverride = com.blah.shared.factories.AdminRequestFactory
It sucks that I have hardcoded full qualified class name in project settings though.
If you guys know more elegant method please let me know.
I too hit the same problem. Basically I have 3 GWT modules 1. Main module and in the second module I have the requestFactory, server domain classes and the client side proxy values. I am pretty much sure that your solution is what I need to put in place. However I am confused how to specify the rootOverride in the maven build phase. Any pointers in the structure of pom.xml would be immensely helpful.
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.