Social Authentication crashes after obfuscating with proguard - facebook

I have an application which uses social authentication (Twitter and Facebook). Before publishing it in app store I used proguard to obfuscate my code. All features work fine except authentication of Facebook and Twitter. As soon as I click on Login with facebook or login with twitter button the application crashes with message Unfortunately "APP Name" has stopped.
My twitter authentication class extends Activity and TwiterProfile.java class extends fragments.
here is my proguard configuration
-injars bin/classes
-injars libs
-outjars bin/classes-processed.jar
-libraryjars libs\ksoap2-android-assembly-2.4-jar-with-dependencies.jar
-libraryjars libs\twitter4j-core-4.0.1.jar
-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic
-keepattributes *Annotation*
-dontwarn twitter4j.**
-dontwarn org.xmlpull.v1.**
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.support.v4.app.ListFragment
-keep public class * extends android.app.Fragment
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.content.Context {
public void *(android.view.View);
public void *(android.view.MenuItem);
}
-keepclassmembers class * implements android.os.Parcelable {
static ** CREATOR;
}
-keepclassmembers class **.R$* {
public static <fields>;
}
-keepclassmembers class * {
#android.webkit.JavascriptInterface <methods>;
}
Here is twitterauthentication.java which is called from TwitterProfile.java class
public class TwitterAuthenticate extends Activity{
private WebView webView;
public static String EXTRA_URL = "extra_url";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webview);
setTitle("Twitter");
final String url = this.getIntent().getStringExtra(EXTRA_URL);
if (null == url) {
Log.e("Twitter", "URL cannot be null");
finish();
}
webView = (WebView) findViewById(R.id.webView);
webView.setWebViewClient(new MyWebViewClient());
webView.loadUrl(url);
}
class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.contains(getResources().getString(R.string.twitter_callback))) {
Uri uri = Uri.parse(url);
/* Sending results back */
String verifier = uri.getQueryParameter(getString(R.string.twitter_oauth_verifier));
Intent resultIntent = new Intent();
resultIntent.putExtra(getString(R.string.twitter_oauth_verifier), verifier);
setResult(RESULT_OK, resultIntent);
/* closing webview */
finish();
return true;
}
return false;
}
}
}

Related

#Inject constructor with parameters

I saw a method of using #inject annotation with parameter constructor. I found no use in #module in all parts of the project. I don't understand how this code injects or provides parameters in the constructor.
Can you help me analyze it?
Where is the datamanager provided?
In the whole project, #module + #provide is not used to provide datamanager. I only know that #inject can only annotate the parameterless constructor. I don't know where to instantiate the parameterless datamanager object. Thank you for your help
application:
public class Scallop extends Application {
private ApplicationComponent applicationComponent;
#Override
public void onCreate() {
super.onCreate();
applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}
application module:
#Module
public class ApplicationModule {
private Scallop application;
public ApplicationModule(Scallop application) { // 提供类的构造器,传入Applicaton
this.application = application;
}
#Provides
#Singleton
Application provideApplication() {
return application;
}
#Provides
#ApplicationContext
Context provideContext() {
return application;
}
#Provides
#Singleton
Retrofit provideRetrofit() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return retrofit;
}
#Provides
#Singleton
GankIOService provideGankIOService(Retrofit retrofit) {
return retrofit.create(GankIOService.class);
}
}
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
Application getApplication();
DataManager getDataManager();
}
```
one class:
#Singleton
public class DataManager {
private GankIOService gankIOService;
private PreferencesHelper preferencesHelper;
#Inject
public DataManager(GankIOService gankIOService, PreferencesHelper preferencesHelper) {
this.gankIOService = gankIOService;
this.preferencesHelper = preferencesHelper;
}
}
fragment module:
#FragmentScope
#Component(modules = FragmentModule.class, dependencies = ApplicationComponent.class)
public interface FragmentComponent {
void inject(HomeFragment homeFragment);
void inject(GanHuoPageFragment pageFragment);
void inject(XianDuFragment xianDuFragment);
void inject(XianDuPageFragment xianDuPageFragment);
void inject(PicturesFragment picturesFragment);
void inject(MoreFragment moreFragment);
}
#FragmentScope
#Documented
#Scope
#Retention(value = RetentionPolicy.RUNTIME)
public #interface FragmentScope {
}
```
here Can't understand constructor with parameter is #inject
public class GanHuoPagePresenter extends BasePresenter<GanHuoPageContract.View>
implements GanHuoPageContract.Presenter {
private DataManager dataManager;
private Disposable disposable;
#Inject
public GanHuoPagePresenter(DataManager dataManager) { // here here
this.dataManager = dataManager;
}
#Override
public void detachView() {
super.detachView();
if (disposable != null) {
disposable.dispose();
}
}
#Override
public void getGanHuo(String category, final int page) {
final List<GanHuo> ganHuoList = new ArrayList<>();
Observable<BaseResponse<GanHuo>> observable = dataManager.getGanHuo(category, page);
disposable = observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.concatMap(new Function<BaseResponse<GanHuo>, ObservableSource<GanHuo>>() {
#Override
public ObservableSource<GanHuo> apply(#NonNull BaseResponse<GanHuo> ganHuoBaseResponse)
throws Exception {
return Observable.fromIterable(ganHuoBaseResponse.getResults());
}
}).filter(new Predicate<GanHuo>() {
#Override
public boolean test(#NonNull GanHuo ganHuo) throws Exception {
return !ganHuo.getType().equals("福利");
}
}).subscribe(new Consumer<GanHuo>() {
#Override
public void accept(GanHuo ganHuo) throws Exception {
ganHuoList.add(ganHuo);
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
getView().showError(throwable.getMessage());
}
}, new Action() {
#Override`enter code here`
public void run() throws Exception {
getView().showList(ganHuoList, page);
}
});
}
}
This is how it is used in V in MVP mode:
#Inject GanHuoPagePresenter presenter
That's constructor injection. By marking a constructor with #Inject Dagger knows about the object and can create it when needed. There's no need for modules, e.g. the following is a valid Dagger setup to create some Foo.
public class Foo {
#Inject
public Foo() {}
}
#Component
interface MyComponent {
Foo getFoo();
}
That's not true that #Inject can only annotate the parameterless constructor. From documentation
Injectable constructors are annotated with #Inject and accept zero or more dependencies as arguments.
I found "your" project on Github so let's see where dependencies for GanHuoPagePresenter come from.
#Inject
public GanHuoPagePresenter(DataManager dataManager) {
this.dataManager = dataManager;
}
#Inject
public DataManager(GankIOService gankIOService,PreferencesHelper preferencesHelper){
// gankIOService is provided by ApplicationModule and preferencesHelper uses constructor injection
this.gankIOService = gankIOService;
this.preferencesHelper = preferencesHelper;
}
#Inject
public PreferencesHelper(#ApplicationContext Context context){
// context is provided again by ApplicationModule
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
}

Eclipse cannot see beyond Beans' models' fields from AbstractBean/AbstractEntity in Facelets

I am running jee-2019-06 version of Eclipse. Here is my Model-Bean-Facade structure:
I am not including getters/setters for brevity.
My Identifiable:
/** Identifiable interface for Entities; used for DAO - Service transitions. */
public interface Identifiable<T extends Serializable> extends Serializable {
public T getId(); // identifiable field
public String getTitle(); // user friendly name (maybe different from actual entity's name)
public String getName(); // every entity has a name
public String getDescription(); // every entity should have a description
}
My Abstract Bean:
public abstract class AbstractBean<T extends Identifiable<?>> {
protected final transient Logger log = Logger.getLogger(this.getClass());
private final Class<T> clazz;
private T model;
public AbstractBean(final Class<T> clazz) {
this.clazz = clazz;
}
protected T createInstance() {
try {
return this.clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
this.log.error("[" + this.getClass().getSimpleName() + ".createInstance()] : Error : {} {}", e.getMessage(), e);
return null;
}
}
protected AbstractFacade<T> getFacade() {
return null;
}
}
My Abstract Facade:
#Transactional
public abstract class AbstractFacade<T extends Identifiable<?>> {
protected final transient Logger log = Logger.getLogger(this.getClass());
protected final Class<T> clazz;
public AbstractFacade(final Class<T> clazz) {
this.clazz = clazz;
}
}
My Bean:
#Named
#ViewScoped
public class CarBean extends AbstractBean<Car> {
#Inject
private CarFacade facade;
public CarBean(){
super(Car.class);
}
#Override
public CarFacade getFacade() {
return this.facade;
}
}
My AbstractEntity:
#MappedSuperclass
public abstract class AbstractEntity implements Identifiable<Integer> {
private Integer id;
private String name;
private String description;
public AbstractEntity() {
}
}
My Entity:
public class Car extends AbstractEntity {
public Car() {
}
}
I have no problems in showing the value to the user.
I have problems in validation and hyperlink in Eclipse:
<h:outputText value="#{carBean.model.name}" />
Facelet validator cannot validate name of model. It yellow underlines name. Also, I cannot Ctrl + click to activate hyperlink on name.
I saw on another developer's eclipse that both of my problems were not issues at all. I compared all the tools installed in both Eclipses and could not find anything relevant.
My question: what tools do I have to install or what settings/adjustments am I missing?
Please note: I do not want to disable the validator and I want to be able to hyperlink fields in facelet so that I will access the field using Ctrl + click.
Thank you.

GWTP displays default place on application start even if url say to go to other place

I wonder how to change gwtp behaviour.
When I start gwt app (enter app url in browser) it always displays for me default place. But when I enter url as follow: localhost/app#settings gwtp should open place Settings, but unfortunatelly it displays me Default place.
Url in web browser address points to Settings but the view is from default place.
I would like to gwtp display for me the view from url.
Here is my configuration:
public class UiModule extends AbstractGinModule {
#Override
protected void configure() {
bind(AppView.Binder.class).in(Singleton.class);
bind(Footer.Binder.class).in(Singleton.class);
bind(GatekeeperProtectedMenuPanel.Binder.class).in(Singleton.class);
install(new GinFactoryModuleBuilder().build(MenuEntryFactory.class));
}
public class ClientModule extends AbstractPresenterModule {
#Override
protected void configure() {
bind(RestyGwtConfig.class).asEagerSingleton();
install(new DefaultModule.Builder()//
.defaultPlace(Routing.HOME.url)//
.errorPlace(Routing.ERROR.url)//
.unauthorizedPlace(Routing.LOGIN.url)//
.tokenFormatter(RouteTokenFormatter.class).build());
install(new AppModule());
install(new GinFactoryModuleBuilder().build(AssistedInjectionFactory.class));
bind(CurrentUser.class).in(Singleton.class);
bind(IsAdminGatekeeper.class).in(Singleton.class);
bind(UserLoginGatekeeper.class).in(Singleton.class);
// Load and inject CSS resources
bind(ResourceLoader.class).asEagerSingleton();
}
}
public class AppModule extends AbstractPresenterModule {
#Override
protected void configure() {
install(new UiModule());
// Application Presenters
bindPresenter(AppPresenter.class, AppPresenter.MyView.class, AppView.class, AppPresenter.MyProxy.class);
bindPresenter(HomePresenter.class, HomePresenter.MyView.class, HomeView.class, HomePresenter.MyProxy.class);
bindPresenter(ErrorPresenter.class, ErrorPresenter.MyView.class, ErrorView.class, ErrorPresenter.MyProxy.class);
bindPresenter(TestPresenter.class, TestPresenter.MyView.class, TestView.class, TestPresenter.MyProxy.class);
bindPresenter(PagePresenter.class, PagePresenter.MyView.class, PageView.class, PagePresenter.MyProxy.class);
bindPresenter(SettingsPresenter.class, SettingsPresenter.MyView.class, SettingsView.class, SettingsPresenter.MyProxy.class);
bindPresenter(FilesPresenter.class, FilesPresenter.MyView.class, FilesView.class, FilesPresenter.MyProxy.class);
bindPresenter(AdminAreaPresenter.class, AdminAreaPresenter.MyView.class, AdminAreaView.class, AdminAreaPresenter.MyProxy.class);
bindPresenter(LoginPresenter.class, LoginPresenter.MyView.class, LoginView.class, LoginPresenter.MyProxy.class);
}
}
This happens when I have GateKeeper on place's presenter.
Here is code:
public class UserLoginGatekeeper extends UserLoginModel implements Gatekeeper {
private final CurrentUser currentUser;
#Inject
UserLoginGatekeeper(CurrentUser currentUser) {
this.currentUser = currentUser;
}
#Override
public boolean canReveal() {
return currentUser.isLoggedIn();
}
}
In my main app presenter I execute asynhronous call to server to check is user login. If so I set client variable currentUser.setLoggedIn(true);. Base on this Gatekeeper allow access to restricted part of app.
I think the problem is that my asynhronous call is triggered to late. And GWTP redirect to default place.
Here is my app presenter code:
public class AppPresenter extends TabContainerPresenter<AppPresenter.MyView, AppPresenter.MyProxy> implements AppUiHandlers, CurrentUserChangedHandler, AsyncCallStartHandler, AsyncCallFailHandler,
AsyncCallSucceedHandler {
#ProxyStandard
public interface MyProxy extends Proxy<AppPresenter> {
}
public interface MyView extends TabView, HasUiHandlers<AppUiHandlers> {
void refreshTabs();
void setTopMessage(String string);
void setLoginButtonVisbility(boolean isVisible);
}
#RequestTabs
public static final Type<RequestTabsHandler> SLOT_REQUEST_TABS = new Type<>();
#ChangeTab
public static final Type<ChangeTabHandler> SLOT_CHANGE_TAB = new Type<>();
public static final NestedSlot SLOT_TAB_CONTENT = new NestedSlot();
private static final LoginService service = GWT.create(LoginService.class);
private final PlaceManager placeManager;
private final CurrentUser currentUser;
#Inject
AppPresenter(EventBus eventBus, MyView view, MyProxy proxy, PlaceManager placeManager, CurrentUser currentUser) {
super(eventBus, view, proxy, SLOT_TAB_CONTENT, SLOT_REQUEST_TABS, SLOT_CHANGE_TAB, RevealType.Root);
this.placeManager = placeManager;
this.currentUser = currentUser;
getView().setUiHandlers(this);
onStart();
}
protected void onStart() {
service.isCurrentUserLoggedIn(new MethodCallback<Boolean>() {
#Override
public void onFailure(Method method, Throwable exception) {
MaterialToast.fireToast("Fail to check is current user logged in " + method + " " + exception.getLocalizedMessage());
}
#Override
public void onSuccess(Method method, Boolean response) {
currentUser.setLoggedIn(response);
getView().setLoginButtonVisbility(response);
}
});
};
#ProxyEvent
#Override
public void onCurrentUserChanged(CurrentUserChangedEvent event) {
getView().refreshTabs();
}
#ProxyEvent
#Override
public void onAsyncCallStart(AsyncCallStartEvent event) {
getView().setTopMessage("Loading...");
}
#ProxyEvent
#Override
public void onAsyncCallFail(AsyncCallFailEvent event) {
getView().setTopMessage("Oops, something went wrong...");
}
#ProxyEvent
#Override
public void onAsyncCallSucceed(AsyncCallSucceedEvent event) {
getView().setTopMessage(null);
}
#Override
public void onLogoutButtonClick() {
service.logout(new MethodCallback<Void>() {
#Override
public void onFailure(Method method, Throwable exception) {
MaterialToast.fireToast("Fail to logout " + method + " " + exception.getLocalizedMessage());
}
#Override
public void onSuccess(Method method, Void response) {
MaterialToast.fireToast("You have been Succefully logout");
PlaceRequest request = new PlaceRequest.Builder(placeManager.getCurrentPlaceRequest()).nameToken(Routing.Url.login).build();
placeManager.revealPlace(request);
currentUser.setLoggedIn(false);
getView().setLoginButtonVisbility(false);
}
});
}
}
Working solution:
/**
*
*/
package pl.korbeldaniel.cms.client.gin;
import gwt.material.design.client.ui.MaterialToast;
import org.fusesource.restygwt.client.Method;
import org.fusesource.restygwt.client.MethodCallback;
import pl.korbeldaniel.cms.client.place.Routing;
import pl.korbeldaniel.cms.client.security.CurrentUser;
import pl.korbeldaniel.cms.client.service.LoginService;
import com.google.gwt.core.shared.GWT;
import com.google.inject.Inject;
import com.gwtplatform.mvp.client.Bootstrapper;
import com.gwtplatform.mvp.client.proxy.PlaceManager;
import com.gwtplatform.mvp.shared.proxy.PlaceRequest;
/**
* #author korbeldaniel
*
*/
public class MyBootstrapper implements Bootstrapper {
private final PlaceManager placeManager;
private final CurrentUser currentUser;
private static final LoginService service = GWT.create(LoginService.class);
#Inject
public MyBootstrapper(PlaceManager placeManager, CurrentUser currentUser) {
this.placeManager = placeManager;
this.currentUser = currentUser;
}
#Override
public void onBootstrap() {
GWT.log("OnBootstrap");
service.isCurrentUserLoggedIn(new MethodCallback<Boolean>() {
#Override
public void onFailure(Method method, Throwable exception) {
MaterialToast.fireToast("Fail to check is current user logged in " + method + " " + exception.getLocalizedMessage());
placeManager.revealErrorPlace("Fail to check is current user logged in " + method + " " + exception.getLocalizedMessage());
}
#Override
public void onSuccess(Method method, Boolean response) {
// MaterialToast.fireToast("1Current user is logged in: " +
// response);
currentUser.setLoggedIn(response);
if (response == true) {
placeManager.revealCurrentPlace();
} else {
placeManager.revealPlace(new PlaceRequest.Builder().nameToken(Routing.Url.login).build());
}
}
});
};
}
Yeah, your backend call is asynchronous and most likely the UserLoginGatekeeper code will run before the backend call returns and the user gets redirected to the default page.
There are two solutions:
Use a dynamically generated host page (index.html) and set a javascript variable to the user details by the backend. You can read out the userdetails in a custom Bootstraper implementation and set the CurrentUser.
If you don't want to use a dynamically generated host page, you can also move the backend call isCurrentUserLoggedIn intot he custom Bootstrapper implementation and in the onSuccess callback reveal the first page (like in the above linked GWTP documentation)

Proguard stops Javascript in WebView from working

I have a class JSBridge (an inner class) which is a javascript interface:
private class JsBridge implements JsCallback {
/**
* #param handlerName method required
* #param jsonData data passed through from javascript
* #param jsCallback A callback to trigger when handler specified by handlername has finished, could be null
*/
#JavascriptInterface
public void callHandler(final String handlerName, final String jsonData, final String jsCallback) {
Log.d(App.TAG, "Bridge call from JS, received " + handlerName);
}
#JavascriptInterface
public void onPageLoad(final String pageName) {
Log.d(App.TAG, "Bridge call from JS, received onPageLoad - we have the page name " + pageName);
}
This works fine until I do a release build with proguard. I've tried following some other SO answers and have added the following lines to my proguard file, but it has not helped. The result is the debug version I get the callbacks, the release version I get no callbacks.
-keep public class * implements com.mixcloud.player.view.JsCallback
-keepclassmembers class * implements com.mixcloud.player.view.JsCallback {
<methods>;
}
-keep public class * implements com.mixcloud.player.view.JsCallback
-keepattributes *Annotation*
-keepattributes JavascriptInterface
-keep public class com.mixcloud.player.view.JSRefreshWebView
-keep public class com.mixcloud.player.view.JSRefreshWebView$JsBridge
-keep public class * implements com.mixcloud.player.view.JSRefreshWebView$JsBridge
-keepclassmembers class * implements com.mixcloud.player.view.JSRefreshWebView$JsBridge {
<methods>;
}
If your Javascript interface methods are annotated with #JavascriptInterface, you can preserve them with
-keepclassmembers class * {
#android.webkit.JavascriptInterface <methods>;
}

GWT Resizable Composite

I'm trying a simple experiment with ResizableComposite by logging width & height of the widget, but I'm not getting any response.
ResizableFlowPanel
public class ResizableFlowPanel extends FlowPanel implements RequiresResize, ProvidesResize {
public ResizableFlowPanel() {
super();
}
#Override
public void onResize() {
GWT.log(this.getOffsetHeight() +","+this.getOffsetWidth());
}
}
AppBody.java
public class AppBody extends ResizeComposite implements RequiresResize,
ProvidesResize {
private static AppBodyUiBinder uiBinder = GWT.create(AppBodyUiBinder.class);
public AppBody() {
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public void onResize() {
GWT.log(this.getOffsetHeight() + "," + this.getOffsetWidth());
super.onResize();
}
interface AppBodyUiBinder extends UiBinder<Widget, AppBody> {
}
}
AppBody.ui.xml
<ui:UiBinder ...>
<e:ResizableFlowPanel styleName="{bundle.appBodyStyle.app_body}">
</e:ResizableFlowPanel>
</ui:UiBinder>
When I resize the browser, I'm not getting any log messages.