Skip to content

Commit

Permalink
Merge branch 'master' of github.com:wizcorp/phonegap-facebook-plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
aogilvie committed Sep 29, 2014
2 parents 26c2755 + 0ccdfb3 commit a948725
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 96 deletions.
14 changes: 9 additions & 5 deletions README.md
Expand Up @@ -8,6 +8,15 @@ The Facebook plugin for [Apache Cordova](http://incubator.apache.org/cordova/) a
* This plugin is built for
* iOS FacebookSDK 3.16.1
* Android FacebookSDK 3.16.0
* GitHub URL : [https://github.com/Wizcorp/phonegap-facebook-plugin/](https://github.com/Wizcorp/phonegap-facebook-plugin/)

## << --- Cordova Registry Warning [iOS]

****Installing this plugin directly from Cordova Registry results in Xcode using a broken `Facebook.framework`, this is because the current publish procedure to NPM breaks symlinks [CB-6092](https://issues.apache.org/jira/browse/CB-6092). Please re-add facebook.framework to Xcode.****

## ------------------------------------------ >>

------------------------------------------

## Facebook Requirements and Set-Up

Expand All @@ -25,11 +34,6 @@ To use this plugin you will need to make sure you've registered your Facebook ap

`platforms/android` and `platforms/ios` contain example projects and all the native code for the plugin for both Android and iOS platforms. They also include versions of the Android and iOS Facebook SDKs. These are used during automatic installation.

#### Adobe PhoneGap Build

If using this plugin on Adobe PhoneGap Build you can ignore the instructions below and go straight to the
PhoneGap Build documentation available [here] (https://build.phonegap.com/plugins/257).

## API

### Login
Expand Down
6 changes: 3 additions & 3 deletions platforms/android/AndroidManifest.xml
Expand Up @@ -2,15 +2,15 @@
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" android:windowSoftInputMode="adjustPan" package="io.cordova.hellocordova" xmlns:android="http://schemas.android.com/apk/res/android">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:debuggable="true" android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name">
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" />
<application android:allowBackup="false" android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/app_name" android:name="HelloCordova" android:theme="@android:style/Theme.Black.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/fb_app_id" />
<activity android:label="@string/fb_app_name" android:name="com.facebook.LoginActivity" />
<activity android:label="@string/fb_app_name" android:name="com.facebook.LoginActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
</application>
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" />
</manifest>
237 changes: 157 additions & 80 deletions platforms/android/src/org/apache/cordova/facebook/ConnectPlugin.java
Expand Up @@ -30,12 +30,16 @@
import com.facebook.FacebookDialogException;
import com.facebook.FacebookException;
import com.facebook.FacebookOperationCanceledException;
import com.facebook.FacebookRequestError;
import com.facebook.FacebookServiceException;
import com.facebook.Request;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.UiLifecycleHelper;
import com.facebook.model.GraphObject;
import com.facebook.model.GraphUser;
import com.facebook.widget.FacebookDialog;
import com.facebook.widget.WebDialog;
import com.facebook.widget.WebDialog.OnCompleteListener;

Expand All @@ -62,9 +66,13 @@ public class ConnectPlugin extends CordovaPlugin {
private String method;
private String graphPath;
private String userID;
private UiLifecycleHelper uiHelper;
private boolean trackingPendingCall = false;

@Override
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
//Initialize UiLifecycleHelper
uiHelper = new UiLifecycleHelper(cordova.getActivity(), null);

// Init logger
logger = AppEventsLogger.newLogger(cordova.getActivity());
Expand Down Expand Up @@ -102,15 +110,51 @@ public void call(Session session, SessionState state, Exception exception) {
@Override
public void onResume(boolean multitasking) {
super.onResume(multitasking);
uiHelper.onResume();
// Developers can observe how frequently users activate their app by logging an app activation event.
AppEventsLogger.activateApp(cordova.getActivity());
}

protected void onSaveInstanceState(Bundle outState) {
uiHelper.onSaveInstanceState(outState);
}

public void onPause() {
uiHelper.onPause();
}

@Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
Log.d(TAG, "activity result in plugin");
Session.getActiveSession().onActivityResult(cordova.getActivity(), requestCode, resultCode, intent);
if (trackingPendingCall) {
uiHelper.onActivityResult(requestCode, resultCode, intent, new FacebookDialog.Callback() {
@Override
public void onError(FacebookDialog.PendingCall pendingCall, Exception error, Bundle data) {
Log.e("Activity", String.format("Error: %s", error.toString()));
handleError(error);
}

@Override
public void onComplete(FacebookDialog.PendingCall pendingCall, Bundle data) {
Log.i("Activity", "Success!");
handleSuccess(data);
}
});
} else {
Session session = Session.getActiveSession();

if (session != null && (loginContext != null || session.isOpened())) {
session.onActivityResult(cordova.getActivity(), requestCode, resultCode, intent);
}
}
trackingPendingCall = false;
}

@Override
Expand Down Expand Up @@ -248,7 +292,7 @@ public void call(Session session, SessionState state, Exception exception) {
Bundle parameters = new Bundle();

Iterator<?> iterator = params.keys();
while (iterator.hasNext() ) {
while (iterator.hasNext()) {
try {
// Try get a String
String value = params.getString((String) iterator.next());
Expand Down Expand Up @@ -330,46 +374,10 @@ public void call(Session session, SessionState state, Exception exception) {

@Override
public void onComplete(Bundle values, FacebookException exception) {
String errMsg;
if (exception != null) {
// User clicked "x"
if (exception instanceof FacebookOperationCanceledException) {
errMsg = "User cancelled dialog";
Log.e(TAG, errMsg);
showDialogContext.error(errMsg);
} else if (exception instanceof FacebookDialogException) {
// Dialog error
errMsg = "Dialog error: " + exception.getMessage();
Log.e(TAG, errMsg);
showDialogContext.error(errMsg);
} else {
// Facebook error
errMsg = "Facebook error: " + exception.getMessage();
Log.e(TAG, errMsg);
showDialogContext.error(errMsg);
}
handleError(exception);
} else {
// Handle a successful dialog:
// Send the URL parameters back, for a requests dialog, the "request" parameter
// will include the resulting request id. For a feed dialog, the "post_id"
// parameter will include the resulting post id.
// Note: If the user clicks on the Cancel button, the parameter will be empty
if (values.size() > 0) {
JSONObject response = new JSONObject();
try {
Set<String> keys = values.keySet();
for (String key : keys) {
response.put(key, values.get(key));
}
} catch (JSONException e) {
e.printStackTrace();
}
showDialogContext.success(response);
} else {
errMsg = "User cancelled dialog";
Log.e(TAG, errMsg);
showDialogContext.error(errMsg);
}
handleSuccess(values);
}
}
};
Expand All @@ -379,21 +387,45 @@ public void onComplete(Bundle values, FacebookException exception) {
public void run() {
WebDialog feedDialog = (new WebDialog.FeedDialogBuilder(me.cordova.getActivity(), Session.getActiveSession(), paramBundle)).setOnCompleteListener(dialogCallback).build();
feedDialog.show();
};

}
};
cordova.getActivity().runOnUiThread(runnable);
} else if (this.method.equalsIgnoreCase("apprequests")) {
Runnable runnable = new Runnable() {
public void run() {
WebDialog requestsDialog = (new WebDialog.RequestsDialogBuilder(me.cordova.getActivity(), Session.getActiveSession(), paramBundle)).setOnCompleteListener(dialogCallback)
.build();
.build();
requestsDialog.show();
};
}
};
cordova.getActivity().runOnUiThread(runnable);
} else if (this.method.equalsIgnoreCase("share") || this.method.equalsIgnoreCase("share_open_graph")) {
cordova.getActivity().runOnUiThread(new WebDialogBuilderRunnable(me.cordova.getActivity(), Session.getActiveSession(), this.method, paramBundle, dialogCallback));
if (FacebookDialog.canPresentShareDialog(me.cordova.getActivity(), FacebookDialog.ShareDialogFeature.SHARE_DIALOG)) {
Runnable runnable = new Runnable() {
public void run() {
// Publish the post using the Share Dialog
FacebookDialog shareDialog = new FacebookDialog.ShareDialogBuilder(me.cordova.getActivity())
.setName(paramBundle.getString("name"))
.setCaption(paramBundle.getString("caption"))
.setDescription(paramBundle.getString("description"))
.setLink(paramBundle.getString("link"))
.setPicture(paramBundle.getString("picture"))
.build();
uiHelper.trackPendingDialogCall(shareDialog.present());
}
};
this.trackingPendingCall = true;
cordova.getActivity().runOnUiThread(runnable);
} else {
// Fallback. For example, publish the post using the Feed Dialog
Runnable runnable = new Runnable() {
public void run() {
WebDialog feedDialog = (new WebDialog.FeedDialogBuilder(me.cordova.getActivity(), Session.getActiveSession(), paramBundle)).setOnCompleteListener(dialogCallback).build();
feedDialog.show();
}
};
cordova.getActivity().runOnUiThread(runnable);
}
} else {
callbackContext.error("Unsupported dialog method.");
}
Expand All @@ -407,7 +439,7 @@ public void run() {
graphPath = args.getString(0);

JSONArray arr = args.getJSONArray(1);

final List<String> permissionsList = new ArrayList<String>();
for (int i = 0; i < arr.length(); i++) {
permissionsList.add(arr.getString(i));
Expand Down Expand Up @@ -458,6 +490,51 @@ public void run() {
return false;
}

private void handleError(Exception exception) {
String errMsg = "Facebook error: " + exception.getMessage();
// User clicked "x"
if (exception instanceof FacebookOperationCanceledException) {
errMsg = "User cancelled dialog";
} else if (exception instanceof FacebookDialogException) {
// Dialog error
errMsg = "Dialog error: " + exception.getMessage();
} else if (exception instanceof FacebookServiceException) {
FacebookRequestError error = ((FacebookServiceException) exception).getRequestError();
if (error.getErrorCode() == 4201) {
// User hit the cancel button in the WebView
// Tried error.getErrorMessage() but it returns null
// if though the URL says:
// Redirect URL: fbconnect://success?error_code=4201&error_message=User+canceled+the+Dialog+flow
errMsg = "User cancelled dialog";
}
}
Log.e(TAG, errMsg);
showDialogContext.error(errMsg);
}

private void handleSuccess(Bundle values) {
// Handle a successful dialog:
// Send the URL parameters back, for a requests dialog, the "request" parameter
// will include the resulting request id. For a feed dialog, the "post_id"
// parameter will include the resulting post id.
// Note: If the user clicks on the Cancel button, the parameter will be empty
if (values.size() > 0) {
JSONObject response = new JSONObject();
try {
Set<String> keys = values.keySet();
for (String key : keys) {
response.put(key, values.get(key));
}
} catch (JSONException e) {
e.printStackTrace();
}
showDialogContext.success(response);
} else {
Log.e(TAG, "User cancelled dialog");
showDialogContext.error("User cancelled dialog");
}
}

private void getUserInfo(final Session session) {
if (cordova != null) {
Request.newMeRequest(session, new Request.GraphUserCallback() {
Expand Down Expand Up @@ -496,7 +573,7 @@ public void onCompleted(Response response) {
}
}
};

//If you're using the paging URLs they will be URLEncoded, let's decode them.
try {
graphPath = URLDecoder.decode(graphPath, "UTF-8");
Expand Down Expand Up @@ -550,50 +627,50 @@ private void onSessionStateChange(SessionState state, Exception exception) {
private boolean isPublishPermission(String permission) {
return permission != null && (permission.startsWith(PUBLISH_PERMISSION_PREFIX) || permission.startsWith(MANAGE_PERMISSION_PREFIX) || OTHER_PUBLISH_PERMISSIONS.contains(permission));
}

/**
* Create a Facebook Response object that matches the one for the Javascript SDK
* @return JSONObject - the response object
*/
public JSONObject getResponse() {
String response;
Session session = Session.getActiveSession();
if (session != null && session.isOpened()) {
Date today = new Date();
long expiresTimeInterval = (session.getExpirationDate().getTime() - today.getTime()) / 1000L;
long expiresIn = (expiresTimeInterval > 0) ? expiresTimeInterval : 0;
response = "{"+
"\"status\": \"connected\","+
"\"authResponse\": {"+
"\"accessToken\": \""+session.getAccessToken()+"\","+
"\"expiresIn\": \""+expiresIn+"\","+
"\"session_key\": true,"+
"\"sig\": \"...\","+
"\"userID\": \""+this.userID+"\""+
"}"+
"}";
} else {
response = "{"+
"\"status\": \"unknown\""+
"}";
}

try {
return new JSONObject(response);
} catch (JSONException e) {
e.printStackTrace();
}
return new JSONObject();
}
String response;
Session session = Session.getActiveSession();
if (session != null && session.isOpened()) {
Date today = new Date();
long expiresTimeInterval = (session.getExpirationDate().getTime() - today.getTime()) / 1000L;
long expiresIn = (expiresTimeInterval > 0) ? expiresTimeInterval : 0;
response = "{"
+ "\"status\": \"connected\","
+ "\"authResponse\": {"
+ "\"accessToken\": \"" + session.getAccessToken() + "\","
+ "\"expiresIn\": \"" + expiresIn + "\","
+ "\"session_key\": true,"
+ "\"sig\": \"...\","
+ "\"userID\": \"" + this.userID + "\""
+ "}"
+ "}";
} else {
response = "{"
+ "\"status\": \"unknown\""
+ "}";
}

try {
return new JSONObject(response);
} catch (JSONException e) {

e.printStackTrace();
}
return new JSONObject();
}

private class WebDialogBuilderRunnable implements Runnable {
private Context context;
private Session session;
private String method;
private Bundle paramBundle;
private OnCompleteListener dialogCallback;

public WebDialogBuilderRunnable(Context context, Session session, String method, Bundle paramBundle, OnCompleteListener dialogCallback) {
this.context = context;
this.session = session;
Expand Down

0 comments on commit a948725

Please sign in to comment.