Xamarin Forms and Facebook Android SDK issues - android

I'm working on Xamarin.Forms app with Parse backend. I am trying to integrate Facebook Android SDK into that. What I want to do is to get the access token natively on each device, and push that access token to Parse.com. For that I need to use official facebook sdk binding for Xamarin. I use dependency injection for that. so I have IFacebookService
public interface IFacebookService
{
Task<string> GetFacebookToken();
void LogOut();
}
And on each platform I implement FacebookService and inject that implementation. On iOS I had no problems. On Android the problem is that even though the facebook UI is shown, I don't receive the callbacks inside my implementation of FacebookService. I think that has something to do with how Android manages callbacks as well as how Xamarin.Forms creates activities. Let me go through the code. Here is the portion of code to request login from Facebook
var callbackManager = CallbackManagerFactory.Create();
//Here I instantiate my own implementation of IFacebookCallback
//nothing fancy here, I've just implemented the required methods with Console.WriteLine();
var loginCallback = new FacebookCallback(() => _loginInProgress = false);
//Register callbackManager and my instance of loginCallback
LoginManager.Instance.RegisterCallback (callbackManager, loginCallback);
//Here is the important part. I need an activity to show the login UI
//Xamarin forms provides me with this method.
var activity = Xamarin.Forms.Forms.Context as Activity;
//I request login
LoginManager.Instance.LogInWithReadPermissions(activity, new string[] { "public_profile", "email", "user_friends" });
So, I believe the problem is within this line
var activity = Xamarin.Forms.Forms.Context as Activity;
In the debugger I see that MainActivity is returned, which is my entry point (MainLauncher = true), and where I call Xamarin Form's initialisation methods
//Setup Xamarin forms
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new FormsApp());
The initial page that is registered in FormsApp is call LoginPage. So I believe that it is loaded as a fragment inside main activity. So, perhaps I'll need to do something like this
LoginManager.Instance.LogInWithReadPermissions(LOGIN_PAGE_FRAGMENT,......);
because in facebook sdk there are separate versions for activity and fragment. I don't know exactly how to get LOGIN_PAGE_FRAGMENT, perhaps even the issue is in some other place, which I don't understand.
Do you have any ideas what can cause the issue?

I've resolved the issue! I've found something similar here
Although my approach is a little different, but the main issue was that I needed to add the implementation of OnActivityResult to the MainActivity and create CallbackManager inside the MainActivity and delegate the OnActivityResult to that CallbackManager. So in MainActivity I added this property
public ICallbackManager CallbackManager { get; private set; }
Then I've overridden OnActivityResult like this
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
CallbackManager.OnActivityResult(requestCode, (int)resultCode, data);
}
Then I've replaced the previous login code with this
var loginCallback = new FacebookCallback(() => _loginInProgress = false);
var activity = Xamarin.Forms.Forms.Context as MainActivity;
LoginManager.Instance.RegisterCallback (activity.CallbackManager, loginCallback);
LoginManager.Instance.LogInWithReadPermissions(activity, new string[] { "public_profile", "email", "user_friends" });
And Everything worked! Hope this will help someone.

Related

Flutter - Is possible to import a Fragment inside a Flutter App?

In Flutter is possible to call Java code from Dart. Also, the plugin android_intent allows to start a Java Android Activity using Dart code
But, if we want to use an Android Fragment inside a Flutter Widget, is this possible? How can we do that?
Or the only way to use Fragments is declaring a new Activity in Java, and call to start the Activity in Flutter? (Like I said at the beginning)
So far I couldn't find any way to implement directly implement, in a straight forward manner, android components inside a flutter app. However is possible the opposite things, that is using a Flutter fragment inside an android application. So I can propose you a workaround for this problem that may lead to the same result:
use a method channel to start a new android activity:
void startAndroidActivity() async {
//TODO: fix result type, etc.
dynamic result = await MethodChannel("CHANNEL_X").invokeMethod('METHOD');
}
public class MainActivity extends FlutterActivity {
private MethodChannel.Result result;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new MethodChannel(getFlutterView(), "CHANNEL_X").setMethodCallHandler((call, result) -> {
if (call.method.equals("METHOD")) {
Intent intent = new Intent(this, MyActivity.class);
this.result = result;
startActivityForResult(intent, data);
}
});
GeneratedPluginRegistrant.registerWith(this);
}
//TODO: Handle result
}
Implement your android components and import the flutter fragment. For this topic, I leave you this reference: https://flutter.dev/docs/development/add-to-app/android/add-flutter-fragment
Another reference I can give you is this one, that maybe can allow you to import what you want in Flutter, but it requires a bit more time: https://medium.com/#KarthikPonnam/build-your-own-plugin-using-platformviews-flutter-5b42b4c4fb0a

Get parameters from android to unity

I have a problem, i want to send a parameter (int) from an app of build in android studio and receive it in an app build it in unity.
The apps work like this, you open the android app, press a botom and open the second app, i send and intent when i open the unity app but idkhow to recieve the param.
I know that are some questions about this but didn't work or maybe idk how to implement it to my code.
This is how i send the param
Java app
Intent launchIntent = getPackageManager().getLaunchIntentForPackage("com.bodyar");
if(user!=null){
launchIntent.putExtra(Constant.TYPE,user.getLearningStyleId());
}else{
launchIntent.putExtra(Constant.TYPE,Constant.VISUAL);
}
startActivity(launchIntent);
but i dont know how to receive the value. I tried the stuff of UnityPlayer.UnitySendMessage(), but u just get an error from that
And the funciton of the Script that it´s attached to GameObjectUI is this
public void TipoTest(string token){
prueba.text = token;
}
And when i export the unity project to android, in the method OnCreate I recieve the params like this
public class UnityPlayerActivity extends Activity {
protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code
// Setup activity layout
#Override protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
mUnityPlayer = new UnityPlayer(this);
setContentView(mUnityPlayer);
mUnityPlayer.requestFocus();
}
#Override protected void onNewIntent(Intent intent) {
// To support deep linking, we need to make sure that the client can get access to
// the last sent intent. The clients access this through a JNI api that allows them
// to get the intent set on launch. To update that after launch we have to manually
// replace the intent with the one caught here.
setIntent(intent);
}
}
And It works but idk how to pass the variable to unity script

Android Facebook login not being processed

I'm using the latest Facebook Android SDK to authenticate my users, and I'm running into this issue.
I have a root activity set up, with a custom ActivityResult handler system (basically, fragments can register and remove ActivityResultHandlers for specific results, this way handling the result of inter-activity requests within a fragment). I've expanded this with the Facebook CallbackManager, the way it is described in the SDK documentation:
In my activity, I have this:
#Override
void onCreate(Bundle bundle) {
[...]
setContentView(R.layout.activity);
FacebookSdk.sdkInitialize(getApplicationContext());
facebookCallbackManager = CallbackManager.Factory.create();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
for (Map.Entry<Integer, ActivityResultHandler> entry : activityResultHandlers.entrySet()) {
if (entry.getKey() == requestCode)
entry.getValue().onActivityResultCustom(requestCode, resultCode, data);
}
super.onActivityResult(requestCode, resultCode, data);
facebookCallbackManager.onActivityResult(requestCode, resultCode, data);
}
And in my fragment, I do this:
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
[...]
LoginManager.getInstance().registerCallback(
((MainActivity)getActivity()).getFacebookCallbackManager(),
new FacebookCallback<LoginResult>() { [...] }
);
}
Then I call the LoginManager to begin authentication once a button is pressed (I'm using custom graphics, so FacebookLoginButton is out of question unfortunately).
LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("email","user_friends","public_profile"));
Now, this part works fine, I can see in the debugger that the facebookCallbackManager.onActivityResult() method is called. However, stepping inside, I see that the LoginManager is registered for a specific response code (let's say, 64206), while the SDK returns with a totally different request code (129742), and thus, the LoginManager callback is not handled.
What am I doing wrong here?
Move this portion. You need to init Facebook SDK before setContentView.
setContentView(R.layout.activity);
FacebookSdk.sdkInitialize(getApplicationContext());
To this
FacebookSdk.sdkInitialize(getApplicationContext());
setContentView(R.layout.activity);
So the solution was pretty simple - move the whole processing into the Fragment itself, and only do the SDK initialization in the main Activity.

Android Saripaar issue with fragments (DialogFragment)

I have used Saripaar successfully within activities, but now, when I use it with DialogFragment, it always go to onSuccess even in wrong input as well.
My Fragment is implementing ValidationListener and Validator is initialized in onCreate() of Fragment as well.
Does anyone has idea about its behaviour in fragments..???
Here is my code over view...
public class MyDialogFragment extends DialogFragment implements ValidationListener {
// Declaring validator
private Validator validator;
// views to validate
#Required(order = 1)
#TextRule(order = 5, minLength = 6, message = "Enter at least 6 characters.")
private EditText nameEditText;
#Required(order = 2)
private EditText addressEditText;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initializing validation process
validator = new Validator(getActivity()); /*====*/
validator.setValidationListener(this);
}
positiveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Validating on positive button event
validator.validate();
}
});
}
// Here are the validation listener methods to implemented
// Just copy pasted from you github account tutorial page
}
Every thing seems right...onSuccess event is invoking perfectly everytime...Don't know what is the issue actually, or where im doing something wrong...
One thing i suspect is, call to getActivity() in line validator = new Validator(getActivity()); might cause issue, like your implementation is depending on context of activity, and in dialog fragment, we are out of context some what...well, you can guess it better...:)
Try this,
validator = new Validator(this); /*====*/
instead of
validator = new Validator(getActivity()); /*====*/
Also, please use the latest source. The jar is a bit outdated. Let me know if this helps.
Add an additional "if" to ask if the "controller" was of the type "support" fragment, in cases where the "native fragment" is not used, doing this it is possible to do the validations also in this class fragment
here my Validator.java
public Validator(final Object controller) {
assertNotNull(controller, "controller");
...
else if(controller instanceof android.support.v4.app.Fragment){
Activity activity = (Activity) ((android.support.v4.app.Fragment) controller).getContext();
mValidationContext = new ValidationContext(activity);
}
}
update
now no change is necessary to support android.support.v4.app.Fragment, my pull request for change was accepted :)
https://github.com/ragunathjawahar/android-saripaar/pull/205/commits/673b7ea7174848b96bce1ae82fa2118d1af9f128

java.lang.NullPointerException for static field in Android library project

First to explain how projects are setup:
Android Library project with two classes:
UserActivity - uses static field in HolderClass
HolderClass - this one has static field Data
Android Application that references Library project, has only one class:
StarterActivity - when app is started, in onCreate it sets static field Data to some value, and it starts UserActivity
Now, the problem is: sometimes I get java.lang.NullPointerException for that static field Data - as if I never initialized it (or value got deleted in meantime). It never happened on my test device, but I keep getting error reports from client devices. I can only guess how that happens - maybe user navigates away from app, then comes back and system recreates whole application context, but in that context HolderClass has empty static field Data?
My question:
Is initialization of that static field from Activity's onCreate wrong approach? Should I put data in ApplicationContext? Or do something else?
I am open for all suggestions.
P.S. If you have problem visualizing from description, here is how everything I've said would look in code:
// IN ANDROID APP PROJECT
public class StarterActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// just start activity in library
Intent myIntent = new Intent(this, AutolaunchActivity.class);
startActivityForResult(myIntent, 1);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// exit when activity from library exits
finish();
}
}
// IN LIBRARY PROJECT
public class HolderClass {
public static String Data;
}
public class UserActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// init layout
}
public void someButtonClicked() {
HolderClass.Data.trim();
}
}
The usual ways of sharing data between activities is documented here. The intermittent nature of the error suggests a timing problem to me. Are you using threads in some of your initialization? Also, do you know if the NPE happening in StarterActivity or UserActivity?
OK, this was basically the problem of global variables - in the end I've solved it by reading this answer: How to declare global variables in Android?

Categories

Resources