I have an interaction between UI Fragment and background Service.
I use EventBus.
Of course, if Activity is stopped/killed, then there are no subscribers.
Here's the code so you understand:
public class LocationService extends Service {
//...
EventBus.getDefault().post(new MessageEventLocationClient(data));
}
public class ClientFragment extends Fragment {
//...
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEventLocationClient event) {
// update UI
textViewLastSentData.setText(event.trackData.lastLatLon());
}
}
And all OK.
However, here is the report sent to me from Google Play Developer Console:
Devices with errors 14:
Google Nexus 7 (flo) - Android 5.0
Google Nexus 9 (flounder) - Android 5.0
Google Pixel (sailfish) - Android 7.1
Motorola XT1096 (victara) - Android 4.4
...
Exceptions:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.tim4dev.imokhere/com.tim4dev.imokhere.MainActivity}: org.a.a.e:
Subscriber class com.tim4dev.imokhere.c and its super
classes have no public methods with the #Subscribe annotation
...
What does it mean?
Is this really a problem?
Then what to do?
A similar problem is described here.
UPD. RTM. Thanks to all.
as pointed out, you need to instruct proguard not to remove method annotated with #Subscribe. Proguard will remove them if they are unused and since EventBus will look for them with reflection they will very likely be unused. you can add some directives to your proguard configuration file, from here:
## New rules for EventBus 3.0.x ##
# http://greenrobot.org/eventbus/documentation/proguard/
-keepattributes *Annotation*
-keepclassmembers class ** {
#org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}
Related
I've been facing a problem that seem very common in Android.
My Webview with a custom Javascript interface is not working when the application is in release mode.
I am unable to call JS code from Java.
I feel that the problem is linked to proguard, as the Webview works normally in release mode as soon as I set the "minifyEnabled" to "false".
My proguard mappings are looking like this, I'm not sure if this is alright:
com.company.app.jsBridge.BaseJavascriptInterface ->
com.company.app.jsBridge.BaseJavascriptInterface:
java.util.Map mCallbacks -> a
java.util.Map mHandlers -> b
com.company.app.jsBridge.BridgeWebView mWebView -> c
29:29:void send(java.lang.String,java.lang.String,java.lang.String):0:0 -> send
...
I have already browsed through Stackoverflow related questions such as these, and a few others:
Proguard stops Javascript in WebView from working
How to configure proguard for javascript interface?
Proguard mess Javascript Interface functions when targeting SDK in Android Manifest above 17
I tried applying the answers of these questions and my proguard file now looks like this:
-keepattributes JavascriptInterface
-keepattributes *Annotation*
-keepclassmembers class * {
#android.webkit.JavascriptInterface <methods>;
}
-keepclassmembers class com.company.app.jsBridge.BaseJavascriptInterface {
public *;
}
-keep public class com.company.app.jsBridge.BaseJavascriptInterface
And my interface:
package com.company.app.jsBridge;
public abstract class BaseJavascriptInterface {
// Callbacks to execute after successful JS calls
private final Map<String, IOnBridgeCallback> mCallbacks;
// Handler methods that will be available to the JS
private final Map<String, IBridgeHandler> mHandlers;
private BridgeWebView mWebView;
public BaseJavascriptInterface(Map<String, IOnBridgeCallback> callbacks, Map<String, IBridgeHandler> handlers, BridgeWebView webView) {
mCallbacks = callbacks;
mHandlers = handlers;
mWebView = webView;
}
#JavascriptInterface
public String send(String handlerName, String data) {
//
}
}
Other things that I have tried:
Running on both an emulator and a physical device, as I read that emulators could have a different behaviour with proguard
Using the #Keep annotation on the Javascript interface
Does anybody know what is wrong with my config or if I'm not looking at the right place ? Thanks
I ended up finding the solution by myself with the help of this post : Proguard issue while using GSON
I needed to preserve both the Javascript Interface in Proguard like I did before, as well as the classes that I used for JSON communication between Java and JS. Gson was unable to properly serialize the data because the models were not preserved.
As soon as I enabled minify, this issue started occurring.
-keepclassmembers class * { *** #{viewModel::onResendClick}(android.view.View); }
This method is a part of the viewmodel but this seems to be weird, I am not able to understand or debug this issue.
I'm using Evernotes android-job library for Scheduling jobs and everything works fine but, when i want to run a test case that is running with Robolecteric i get this error :
com.evernote.android.job.JobManagerCreateException: All APIs are disabled, cannot schedule any job
at com.evernote.android.job.JobManager.<init>(JobManager.java:184)
at com.evernote.android.job.JobManager.create(JobManager.java:107)
at com.M.MyApp.MyApplication.onCreate(MyApplication.java:63)
at org.robolectric.android.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:137)
at org.robolectric.RobolectricTestRunner.beforeTest(RobolectricTestRunner.java:290)
at org.robolectric.internal.SandboxTestRunner$2.evaluate(SandboxTestRunner.java:203)
at org.robolectric.internal.SandboxTestRunner.runChild(SandboxTestRunner.java:109)
basically its pointing to line 63 of my application class :
JobManager.create(getApplicationContext()).addJobCreator(new JobMaker());
Just ran into this same issue after updating the Evernote library to 1.1.11
You can just wrap your initialisation of the JobManager in a try catch and swallow the exception, but a better solution is to create a test version of your application class and load that in for your tests.
The steps are described here.
Move line 63 of your application class to a method - called something like setUpJobManager() - and call that in your onCreate. Then override that method in the test version of your application class.
public class TestApplication extends AppController implements TestLifecycleApplication {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void createJobManager() {
}
Then pass the TestApplication class to your robolectric tests. Just make sure you correctly annotate your Robolectric test classes to use the test application class.
#RunWith(RobolectricTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 23, application = TestApplication.class)
I have added two Interstitial ads in my single android application and since I have not uploaded it to play store it is working fine. I want to know that does it create problem after uploading to play store.
It depends, if you do not follow the guidelines of Google, it could pose a problem either by getting banned or by taking your app down. For more information:
https://support.google.com/admob/answer/6066980?hl=en
https://support.google.com/admob/answer/2753860?hl=en
EDIT: Also if you do decide on obfuscating your code (Scrambling your code so that people don't steal your ideas) Then you have to make sure you exclude the code you used to add the ads to your app or they may not work the way you intend them to work. For example if you were using proGuard and wanted to obfuscate your Goolge Ad, it would use something like this in your proguard-project.txt
-keep class com.google.android.gms.**
-dontwarn com.google.android.gms.**
-keep class * extends java.util.ListResourceBundle {
protected Object[][] getContents();
}
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
public static final *** NULL;
}
-keepnames #com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
#com.google.android.gms.common.annotation.KeepName *;
}
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
I've been testing my app on Sony and Nexus devices as well as multiple emulators (API 10 - 19) for several weeks and things seem fine, however, two of my testers (who live remotely) are experiencing crashes during startup and ACRA isn't offering the option to send a crash log email, which leads me to believe it's a crash before ACRA is even instantiated. ACRA works as expected on my devices and emulators and offers to send an email (via default app).
Are Samsung phones doing some special initialization? Am I doing anything in the following code which could cause a crash?
#ReportsCrashes(
formKey = "", // This is required for backward compatibility but not used
mailTo = "crash#mydomain.com",
customReportContent = {
ReportField.APP_VERSION_CODE,
ReportField.APP_VERSION_NAME,
ReportField.ANDROID_VERSION,
ReportField.PHONE_MODEL,
ReportField.CUSTOM_DATA,
ReportField.STACK_TRACE,
ReportField.LOGCAT }
)
public class AppState extends Application {
private static final String DIRECTORY_ROOT = Environment.getExternalStorageDirectory();
private static final String DIRECTORY_PICTURES_APP = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath() + File.separator + "MyApp";
private static final LogConfigurator logConfigurator = new LogConfigurator();
private static final Logger logger = Logger.getLogger(AppState.class);
#Override
public void onCreate() {
super.onCreate();
ACRA.init(this);
// try to create log file and directory; if successful, configure ACRA to include last lines with crash report
if (createLogFile()) {
ACRAConfiguration config = ACRA.getConfig();
config.setApplicationLogFile(LOGGER_FILENAME);
ACRA.setConfig(config);
}
...log4j, database init, etc...
The source for the project is located here on SourceForge.
EDIT #1:
Finally got one of the Samsung Remote Test Lab devices working! Screen still isn't visible, but I can at least see logcat. Here is the reason for the crash:
ERROR AndroidRuntime at org.dumpsterdiver.sync.AppState.onCreate(Unknown Source)
So that means the system is unable to find my Application class? After a bit of Googling similar problems, I think it might be a proguard error (sigh, again), so I've been playing with various suggestions from other answers. None of these have helped so far (still experimenting with various values):
-keep public class org.dumpsterdiver.sync.AppState
-keep public class * extends android.app.Application
-keep public class * extends com.actionbarsherlock.app.SherlockActivity
EDIT #2:
Adding this line to my proguard config file seems to fix the problem:
-keep class * { *; }
But my APK is 500 KB larger (3.7 -> 4.2 MB) and I suspect this probably defeats half the point of using proguard in the first place? Is there a better solution?
After a lot of experimentation, this line was the problem:
-keep public class org.dumpsterdiver.sync.AppState
Changing it to this seems to have done the trick:
-keep public class * extends android.app.Application