Friendly Score Android SDK Integration

The repository provides access to Friendly Score Android SDK. It includes a demo app, the libraries that are needed to create your own app. The documentation also goes through some of the key code included in the DEMO app.

Getting Started

These instructions will help you get started to integrate FriendlyScore Android SDK in your App.

Prerequisites

Android Studio Stable Version.

Supports Android SDK >=16(Jelly Bean)

Pay attention to conflicts arising due to dependencies on different versions.

Currently, SDK dependencies are below. If after integration, Android Studio is giving errors that it cannot find cardView attributes or eventbus or okhtttp. Include them in your app/build.gradle

    dependencies {
        compile 'com.android.support:appcompat-v7:25.3.0'
        //Card Layouts
        compile 'com.android.support:cardview-v7:25.3.0'

        compile 'com.squareup.okhttp3:okhttp:3.6.0'

        compile 'org.greenrobot:eventbus:3.0.0'
        //Dotted View For View pager
        compile 'com.google.code.gson:gson:2.8.0'

        ...
      }

The key things to focus is on having the identical version numbers in your app/build.gradle. If you add any of the dependencies listed above. Also, your

    minSDKVersion should be >=16.

    buildToolsVersion should be "25.0.3".

Friendly Score App Id. You can get one at Friendly Score for Businesses

Social Media Authentication Pre-requisites

Do not forget to add your authentication API keys for Google, Facebook, Twitter(In res/values/strings.xml) and PayPal(In Code).

Remember to change your API Keys to production, when you launch the Apps.

You need to do this only for the Social Media accounts you have enabled for your Friendly Score App.

PLEASE Look clearly at the requested scopes, otherwise, our Servers Will return Internal Server Error and the SDK will log in your Android Studio Console.(Look for messages beginning with "SDKError:")

Generating Hash Keys.

  • Debug Keys

Windows

keytool -exportcert -keystore %HOMEPATH%.android\debug.keystore -alias androiddebugkey | openssl sha1 -binary | openssl base64

MAC OS/UNIX

keytool -exportcert -keystore ~/.android/debug.keystore -alias androiddebugkey | openssl sha1 -binary | openssl base64

  • Release Keys

keytool -exportcert -keystore YOUR_RELEASE_KEY_PATH -alias YOUR_RELEASE_KEY_ALIAS | openssl sha1 -binary | openssl base64

Facebook - Facebook My Apps

Scopes - public_profile, user_friends, email

How to create an App to use Facebook Authentication Follow the Facebook tutorial Facebook Getting Started

#

Google - Google Developer Console Dashboard

Scopes are set in Code(Included as Constants in the SDK)

Create Android API Key Credentials Credentials

  1. Google Calendar API

  2. Analytics API

  3. Google+ API

  4. Gmail API

  5. IdentityToolkit API

  6. Google Drive API

#

Twitter - Twitter My Apps

Scopes - Read, write, and direct messages

These are set in the Access level section of Application Settings

You will need to use the Consumer API Key Listed in the Application Setting, used in the Android App you create.

#

LinkedIn - LinkedIn apps

Scopes - r_basicprofile, r_emailaddress, rw_company_admin, w_share

Create an app and in the authentication section set the above mentioned scopes. You will need your app package name and package hash(mentioned earlier).

#

PayPal - PayPal My Apps

Scopes(Just for information) - openid(Basic Authentication. Its already set), email, phone, address, profile.

Due to the way PayPal Authentication operates please contact us for the PayPal Client ID to use in your Friendly Score, which you can do so on the Slack Channel, https://friendlyscoregroup.slack.com

Create App Using the Downloaded Git Repository

  1. Download the repository and unzip it.
  2. Open Android Studio and Go to File->New->Import Project.
  3. Navigate to the folder where you unzip the repository. Select the 'FriendlyscoreandroidDEMO' folder and press OK.
  4. Let the project get set up. You may have to update gradle version and android support files. Android Studio would directly prompt you.
  5. Once the project is loaded. Go to StartActivity. Add your FriendlyScore App Id as the value of the String. private String appid = "YOUR_FRIENDLYSCORE_APP_ID";
  6. You would need an App Registered to use Facebook, Google, LinkedIn, Twitter and PayPal Authentication with Appropriate Authentication Scopes. The previous section provided links and details on scopes for each of the social media authentication process.
  7. Once you have the appropriate keys and ids, please follow the steps below

7a. For Twitter: add values for in your res/values/strings.xml

  <string name="twitter_consumer_key"></string>
  <string name="twitter_consumer_secret"></string>

7b. For Facebook: add values for in your res/values/strings.xml

  <string name="facebook_app_id"></string>
  <string name="fb_login_protocol_scheme"></string>

7c. For Google: Ensure google-services.json is added to app/ folder.

7d. For PayPal: Please contact us for information on the client_id to use for integrating PayPal.

    private static final String CONFIG_ENVIRONMENT = PayPalConfiguration.ENVIRONMENT_PRODUCTION;
    private static String FSCORE_PROD_CONFIG_CLIENT_ID = "";

7e. For LinkedIn: No variables needed.(Just the LinkedInSDK)

  1. You should be ready. If you have connected a device, run by clicking on the green arrow.

Create App From Scratch

  • Create a new App in Android Studio.Create Android App

  • Keep your app package, it will be needed later.

  • App Registered to use Facebook, Google, LinkedIn, Twitter and PayPal Authentication with Appropriate Authentication Scopes

Add FriendlyScore Android SDK to your project

From the downloaded repository, in the folder FriendlyScoreAndroidSDK are the two .AAR files needed to add FriendlyScore features to your app.

  • FriendlyScoreAndroidSDK-release.aar
  • FriendlyScoreAndroidSDK-UI-release.aar

Create a Library module using the two downloaded libraries.

  1. In Android Studio, choose File->New->New Module.
  2. Select Import .JAR/.AAR Package option and Press Next.
  3. In File Name choose the AAR file in FriendlyScoreAndroidSDK
  4. In Subproject name add the name to the library module. For example FriendlyScoreAndroidSDK and Press Finish.
Add the created library module.
compile project(':FriendlyScoreAndroidSDK')

Follow the above steps for creating and add library module for FriendlyScoreAndroidSDK-UI

Let the project creation finish and sync.

Before integration, please ensure you have followed these steps so you can add the various social authentications to your app.

You would need an App Registered to use Facebook, Google, LinkedIn, Twitter and PayPal Authentication with Appropriate Authentication Scopes. The Social Media Authentication Pre-requisite section provided links and details on scopes for each of the social media authentication process.

  1. Once you have the appropriate keys and ids, please follow the steps below

1a. For Twitter: add values for in your res/values/strings.xml

  <string name="twitter_consumer_key"></string>
  <string name="twitter_consumer_secret"></string>

1b. For Facebook: add values for in your res/values/strings.xml

  <string name="facebook_app_id"></string>
  <string name="fb_login_protocol_scheme"></string>

1c. For Google: Ensure google-services.json is added to app/ folder.

1d. For PayPal: Please contact us for information on the client_id to use for integrating PayPal.

    private static final String CONFIG_ENVIRONMENT = PayPalConfiguration.ENVIRONMENT_PRODUCTION;
    private static String FSCORE_PROD_CONFIG_CLIENT_ID = "";

1e. For LinkedIn: Do nothing.(You need the LinkedInSDK)

#

Once you have the FriendlyScore APP ID and your APP registered with Social Networks and the respective Authentication Keys, you can proceed towards Integration. This flow can also be used to understand the flow of the DEMO app.

#

1. Create an Activity which will start the FriendlyScore UI flow say after clicking a button('Start Scoring' in StartActivity in the demo application). In the DEMO app, this activity sends the user identification, if its a repeat user & the FriendlyScore APP ID

2. Create the FriendlyScore UI. You do that by extending LaunchUI

  public class ClientActivity extends LaunchUI

#### 3. To call FriendlyScore in your onCreate function in ClientActivity

    private final String SESSION_KEY_PREF = "SESSION_KEY_PREF";

    private  String SESSION_KEY_HEADER = "session-key";


    //Used to store and read user state, i.e. such as total score values.
    private final String USER_KEY_PREF = "USER_KEY_PREF";

    private  String USER_KEY_HEADER = "current-user-state";


    @Override
    protected void onCreate(Bundle savedInstanceState) {

    //Your Friendly Score App Id
    String appid = "APPID";
    String session_key = null;

    //One user per device. So Session Key for that user is unique
    session_key = getSessionKey();

    //Entry point to Friendly Score.
    //It is used to retrieve Configurations you set for your Friendly Score App online.
    Credentials credentials = new Credentials(appid,session_key);

    credentials.getInstance();
  }

4. Add the functions that you need to override.

  @Override
  public  void appErrorMessage(AppErrorForClient appErrorForClient){
    Log.d(TAG,String.valueOf(appErrorForClient.getErrorNo()));
    String message = null;
    String title= null;
    switch (appErrorForClient.getErrorNo()){
        case AppErrorForClient.app_id_not_found:
            title = "Check your App Id on Friendly Score";
            message = "Contact App Developer";
            showErrorDialog(message,title);
            break;
        case AppErrorForClient.session_key_not_found:
            title = "User not found";
            message = "Check user data";
            showErrorDialog(message,title);
            break;
        case AppErrorForClient.internalServerError:
            title = "Problem with our servers";
            message = "There was problem with out servers, try again soon";
            showErrorDialog(message,title);
            break;
    }

  }

//Function called when errors are thrown primarily due to user state.
  @Override
  public void userErrorMessage(ErrorForUser errorForUser){
    Log.d(TAG,errorForUser.getErrorMessage());
    String message = null;
    String title= null;
    switch (errorForUser.getErrorNo()){
        case ErrorForUser.no_internet:
            title = "no internet";
            message = "Check Your Internet Connection";
            showErrorDialog(message,title);

            break;
        case ErrorForUser.scoreCalculationError:
            title = "Problem Calculating Score";
            message = "There was problem calculating your score, try again in a few moments";
            showErrorDialog(message,title);

            break;
        case ErrorForUser.noDataToScore:
            title = "Problem Calculating Score";
            message = "Your Profile does not have enough data to calculate the score";
            showErrorDialog(message,title);

            break;
      }
    }

    private void showErrorDialog(String message, String title ){
            AlertDialog.Builder builder = new AlertDialog.Builder(this);

            builder.setMessage(message)
                    .setTitle(title);
            // Add the buttons
            builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    // User clicked OK button
                    //activity.finish();
                    finish();
                }
            });

            // Create the AlertDialog
            AlertDialog dialog = builder.create();

            dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                @Override
                public void onDismiss(DialogInterface dialogInterface) {
                    //activity.finish();
                    //finish();
                }
            });
            dialog.show();
  }

5. You have to implement the function below to connect to the appropriate data source, based on the Connect Button user clicks the button in the FriendlyScore UI.

    @Override
public void setClicked(int networkType, boolean connected) {

    //Log.d(TAG,event.networkType);
    switch (networkType){
        case Constants.GOOGLE_ID:
            signInWithGoogle();
            break;
        case Constants.TWITTER_ID:
            executeTwitterLogin();
            break;
        case Constants.LINKEDIN_ID:
            loginonClick();
            break;
        case Constants.PAYPAL_ID:
            onProfileSharing();
            break;
        case Constants.FACEBOOKL_ID:
            fbLogin();
            break;
    }

An example of implementing Google Authentication is explained in detail later, in the next section.

6. Once you have data from the respective social networks, you have to send the data to FriendlyScore. You need to pass the data along with the identification of Social Network. This can be got using Constants.GOOGLE_AUTH for example. Similarly for other networks.

    new SendToFriendlyScore(currentActivity).execute(info.toString(), Constants.GOOGLE_AUTH);

7. After data is sent to FriendlyScore an Event will be triggered, which you need to handle. This call will have current user state and identification for this user. This identification is the same session key value that was passed in step 3.

    //Called When user completes connecting with any of the data sources
    @Override
    public void handleReceivedTokenScore(ReceivedTokenScore receivedTokenScore){
         storeCurrentUserState(receivedTokenScore);
         storeSessionKey(receivedTokenScore.session_key);
         Log.d(TAG,new Gson().toJson(receivedTokenScore));
     }

#### 8. Once the user completes the final process of authentication, by pressing "See Your Score" button, the SDK will trigger an event that must be handled The event will return a user object with the final score(Out of 1000). From this function based on the score value, you can send the user to the appropriate functionality in your app

    //Function called when the user successfully completes the final scoring
    @Override
    public void getCompletedScore(ScoreCompleted scoreCompleted) {
        Log.d("ClientActivity",""+scoreCompleted.userObject);
    }

9. These functions will help in the implementation of storing and retrieving user state and identification.

  private void storeCurrentUserState(ReceivedTokenScore receivedTokenScore){

        SharedPreferences sessionPreferences = this.getSharedPreferences(USER_KEY_PREF,Context.MODE_PRIVATE);

        SharedPreferences.Editor editor = sessionPreferences.edit();
        editor.putString(USER_KEY_HEADER,new Gson().toJson(receivedTokenScore));
        editor.commit();
  }

 private String getSessionKey(){
        SharedPreferences sessionPreferences = this.getSharedPreferences(SESSION_KEY_PREF,Context.MODE_PRIVATE);

        String session_key = sessionPreferences.getString(SESSION_KEY_HEADER,null);

        return session_key;
 }

 private void storeSessionKey(String session_key){

        SharedPreferences sessionPreferences = this.getSharedPreferences(SESSION_KEY_PREF,Context.MODE_PRIVATE);

        SharedPreferences.Editor editor = sessionPreferences.edit();
        editor.putString(SESSION_KEY_HEADER,session_key);
        editor.commit();
 }

PLEASE Look clearly at the requested scopes, otherwise, our Servers Will return Internal Server Error and the SDK will log in your Android Studio Console.(Look for messages beginning with "SDKError:")

Steps for allowing sign in with Google

1. For the ClientActivity class created before, implement GoogleApiClient.OnConnectionFailedListener.

  public class ClientActivity extends LaunchUI implements
    GoogleApiClient.OnConnectionFailedListener{

    private GoogleApiClient mGoogleApiClient;

    //Used in Google Auth
    private static final int GOOGLE_SIGN_IN_CODE = 9001;

    ...
    }

#### 2. To use Google Sign in, Google Play Services must be upto date. This check can be done in this way.

    //For Google Login, ensure you check for presence of Google Play Services
    @Override
        public  boolean checkGooglePlayServicesVersion(){
            int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

            switch (status){
                case ConnectionResult.SUCCESS:
                    return true;
                case ConnectionResult.SERVICE_MISSING:
                    showGooglePlayServicesErrorAlert(
                            getResources().getString(R.string.no_google_play_services),
                            getResources().getString(R.string.no_google_play_services_title));
                    return false;
                case ConnectionResult.SERVICE_UPDATING:
                    showGooglePlayServicesErrorAlert(
                            getResources().getString(R.string.google_play_services_updating),
                            getResources().getString(R.string.google_play_services_updating_title));
                    return false;
                case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:
                    showGooglePlayServicesErrorAlert(
                            getResources().getString(R.string.google_play_services_update),
                            getResources().getString(R.string.google_play_services_title_update));
                    return false;
                case ConnectionResult.SERVICE_DISABLED:
                    showGooglePlayServicesErrorAlert(
                            getResources().getString( R.string.google_play_services_disabled),
                            getResources().getString(R.string.google_play_services_disabled_title));
                    return false;
                case ConnectionResult.SERVICE_INVALID:
                    showGooglePlayServicesErrorAlert(
                            getResources().getString(R.string.google_play_services_invalid),
                            getResources().getString(R.string.google_play_services_invalid_title));
                    return false;
           }
          return false;
     }

3. Call this function in onCreate, as below.

    checkGooglePlayServicesVersion()

4. Next You need to Set Up Google Auth.

    //The function sets up the process for authentication with Google with
    //appropriate scopes and permissions. This is necessary or it would trigger
    //error by the SDK in computing user score.
    private void setUpGoogle(){
          GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                  .requestIdToken(getString(R.string.default_web_client_id))
                  .requestServerAuthCode(getString(R.string.default_web_client_id))
                  .requestScopes(
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[0]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[1]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[2]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[3]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[4]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[5]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[6]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[7]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[8]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[9]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[10]),
                          new com.google.android.gms.common.api.Scope(Constants.GOOGLE_SCOPES[11])
                  )
                  .requestEmail()
                  .build();
          // [END config_signin]

      mGoogleApiClient = new GoogleApiClient.Builder(this)
            .enableAutoManage(this , this)
            .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
            .build();
      }

      @Override
      public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
          // An unresolvable error has occurred and Google APIs (including Sign-In) will not
          // be available.
          Log.d(TAG, "onConnectionFailed:" + connectionResult);
          //Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show();
      }

5. Cal this function in your onCreate function.

    setUpGoogle();

6. Sign in With Google Function that must be called from the setClicked function described earlier.

  private void signInWithGoogle(){
    mGoogleApiClient.clearDefaultAccountAndReconnect();
    Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
    startActivityForResult(signInIntent, GOOGLE_SIGN_IN_CODE);
  }

6. Handle the Sign in flow result.

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
        if (requestCode == GOOGLE_SIGN_IN_CODE) {
            GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            if (result.isSuccess()) {
                // Google Sign In was successful, authenticate with Firebase
                GoogleSignInAccount account = result.getSignInAccount();

                handleGoogleAuthorization(account);
            } else {

                // Google Sign In failed, update UI appropriately

              //Defined in LaunchUI
                userAuthError(Constants.GOOGLE_AUTH);

              }
          }
      }

      private void handleGoogleAuthorization(GoogleSignInAccount acct){
          //For score calculation using Google Authentication on Android, we need
          //IdToken and ServerAuthorizationCode.
          //Code is Below
              new GoogleServerAuthCodeTask(this).execute(acct.getEmail(),"com.google",acct.getIdToken());
              Log.d(TAG,acct.getIdToken());
      }

7. For score calculation using Google Authentication on Android, we need IdToken and ServerAuthorizationCode. The previous section showed how to get the IdToken. Below is the code to get the ServerAuthorizationCode.

    import android.accounts.Account;
    import android.app.Activity;
    import android.os.AsyncTask;

    import com.google.android.gms.auth.GoogleAuthUtil;
    import com.google.android.gms.auth.UserRecoverableAuthException;

    import org.json.JSONObject;

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.Calendar;

    import FriendlyScore.Constants;
    import FriendlyScore.SendToFriendlyScore;


    public class GoogleServerAuthCodeTask extends AsyncTask<String, Void, JSONObject> {


        String TAG = "GoogleServerAuthCodeTask";

        Activity callAct;
        public GoogleServerAuthCodeTask(Activity act){

            callAct = act;
        }
        @Override
        protected JSONObject doInBackground(String... params) {
            HttpURLConnection urlConnection = null;

            JSONObject googleToken = new JSONObject();

            String mEmail = params[0];
            String mType = params[1];
            String idToken = params[2];
            try {
                URL url = new URL("https://www.googleapis.com/plus/v1/people/me");

                Account account = new Account(mEmail, mType);

                String scope = Constants.GOOGLE_SERVER_CODE_SCOPE;
                String token =  GoogleAuthUtil.getTokenWithNotification(callAct, account, scope,null);



                urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestProperty("Authorization", "Bearer " + token);

                BufferedReader r = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                StringBuilder total = new StringBuilder();
                String line;
                while ((line = r.readLine()) != null) {
                    total.append(line).append('\n');
                }

                googleToken.put("id_token",idToken);
                googleToken.put("access_token",token);

            } catch (UserRecoverableAuthException userAuthEx) {
                // Start the user recoverable action using the intent returned by
                // getIntent()
                //startActivityForResult(userAuthEx.getIntent(), RC_SIGN_IN);

                return null;
            } catch (Exception e) {
                // Handle error
                // e.printStackTrace(); // Uncomment if needed during debugging.
                return null;

            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
            }

            return googleToken;
        }

        @Override
        protected void onPostExecute(JSONObject info) {
            // Store or use the user's email address
            if(info!=null)
                new SendToFriendlyScore(callAct).execute(info.toString(), Constants.GOOGLE_AUTH);
            else{
                //TODO(Inform User to Add Appropriate Message For User)
            }
        }

    }

If you wish to Customize

To change the toolbar back button icon

    setToolbarIcon(R.drawable.my_back_button_icon);

To change the toolbar settings icon

    setOverflowIcon(getResources().getDrawable(R.drawable.my_overflow_menu_icon));

To add menu to your ClientActivity.

    @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.client_menu, menu);
            return true;
        }

values/client_colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <color name="colorPrimary">#455a64</color>

    <color name="colorPrimaryDark">#263238</color>

    <color name="colorAccent">#d33a6d</color>

    <color name="colorCardStart">#d33a6d</color>

    <color name="colorCardEnd">#49326a</color>

    <color name="colorAppBackgroundStart">#313068</color>

    <color name="colorAppBackgroundEnd">#282755</color>

    <color name="colorCompleteButtonStart">#6dcddd</color>

    <color name="colorCompleteButtonEnd">#2196aa</color>

    <color name="complete_button_label_color">#ffffff</color>

    <color name="average_score_bar_color">#e84373</color>

    <color name="your_score_bar_color">#6ecddd</color>

    <color name="bar_background_color">#f6f6f6</color>

    <color name="connectDataColorButtonPress">#20d33a6d</color>

    <color name="info_label_color">#ffffff</color>

    <color name="unselected_pager_color">@android:color/black</color>

    <color name="selected_pager_color">@android:color/white</color>

    <color name="initial_loading_color_start">@android:color/white</color>

    <color name="initial_loading_color_end">@android:color/white</color>

    <color name="toolbar_text_color">@android:color/black</color>

    <color name="toolbar_icon_color">@android:color/white</color>

    <color name="toolbar_background">@color/colorPrimary</color>

</resources>

Additional Functionality & Information

When building a release version of the app, it is necessary to sign it with a key. In Android studio when generating the release version, sign with both v1(jar - to release on devices with OS before Android 7.0) & v2(apk to release on devices with OS Android 7.0 onwards)

You can check the list of users you add online on friendlyscore.com in your business account.
To Generate List of your clients, Follow the instructions Integrate Friendly Score

In order to customize the text of the UI flow please contact us, in the Slack Channel https://friendlyscoregroup.slack.com