Linkedin SDK for Android _ Authentication
Here finally comes the first Android tutorial in a good while, as I’ve been writing more on RESTful webservices and N-Tier achitecture based frameworks for the last weeks. So this is being a special tutorial ! Where we’ll see how to integrate Linkedin SDK and how to authenticate users and retreive user’s information through it.
Next tutorial is a for authentication wtih Facebook API. Then we’ll follow up with Facebook’s Graph API and how to share on Linkedin from your Android app. For now, I had a project on github (KotlinLearning [Part 1]) containing both SDKs integrated and consumed, along with a set of other usefull features. You can just fork it, or if you want to learn how things worked step by step, follow up with the tutorials.
What we’ll build
We’ll create a simple ui for user sign up/sign in through Linkedin API. The logic is we retreive user’s data on registration request,
and store it to whatever storage system we’re using. In this tutorial we’ll use firebase authentication to store our Linkedin user data.
Project setup
- Our project will be as simple as this :
We’ll prepare our simple uis as follows:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" tools:context=".activities.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="bottom"> <com.rey.material.widget.Button android:id="@+id/loginBtn" android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_margin="5dp" android:text="Login" android:textSize="8pt" android:textStyle="bold" fontPath="fonts/graublau_slab.ttf" android:textColor="@color/base_color_2" android:background="@color/base_color_1" android:onClick="onClick"/> <com.rey.material.widget.Button android:id="@+id/signupBtn" android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_margin="5dp" android:text="Create new account" android:textSize="8pt" android:textStyle="bold" fontPath="fonts/graublau_slab.ttf" android:textColor="@color/base_color_1" android:background="@color/base_color_2" android:onClick="onClick"/> </LinearLayout> </LinearLayout>
activity_signup.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <com.rey.material.widget.Button android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#007bb6" android:drawableLeft="@drawable/ic_linkedin_login" android:paddingLeft="10dp" android:text="Continue with linkedin" android:textColor="#FFFFFF" android:onClick="signUpWithLinkedin"/>
activity_login.xml:
the exact same sample ui as activity_signup.
activity_home.xml:
a ui showing after login success. we’ll add read user’s profile picture, last name and first name and display them here.
- and we’ll add Linkedin gradle dependency, then sync the project. Initially Linkedin’s SDK is to be added locally as a module to your android project, until a developer saved our lives and published the code to JitPack as an “unofficial Linkedin SDK” so we can import it as follows :
build.gradle:
compile 'com.github.neurospeech:unofficial-linkedin-sdk-android:v1.1.4'
We’ll also need to add firebase dependencies and other dependencies we’ll be using like Google’s gson library for JSON deserialization, we’ll need it to deserialize the json user object returned by the API into a Java object, as well as some circular image view lib dependecy and other. These are all the dependencies we’ll add to build.gradle:
// material design library compile 'com.github.rey5137:material:1.2.4' // to set custom font compile 'uk.co.chrisjenx:calligraphy:2.3.0' // password visibiuk.co.chrisjenx:calligraphlity toggle compile 'com.github.scottyab:showhidepasswordedittext:0.8' // circular imageView compile 'de.hdodenhof:circleimageview:2.2.0' // to set imageView's src with url compile 'com.squareup.picasso:picasso:2.5.2' // firebase core compile "com.google.firebase:firebase-core:11.8.0" // firebase authentification compile "com.google.firebase:firebase-auth:11.8.0" // facebook api compile('com.facebook.android:facebook-android-sdk:4.27.0') // linkedin API compile 'com.github.neurospeech:unofficial-linkedin-sdk-android:v1.1.4' // firebase database compile 'com.google.firebase:firebase-database:11.8.0' // to deserialize/serialize json ibjects returned by LINKEDIN API compile 'com.google.code.gson:gson:2.8.2'
- We also need to set up a firebase project, as we’ll authenticate a user with the data retreived from Linkedin’s API through firebase manually. (firebase supports Facebook sign-in but not Linkedin). So you will need to create a new project on firebase, download the google-services.json file and put it under your project’s app folder, and set sign-in method Email/Password to enabled on your firebase dashboard (we’ll enable Facebook sign-in method later).
If you are not used to firebase, check out this tutorial.
Creating an application on developer.linkedin.com
- As any other third-party provider, LinkedIn requires you register your app and set all its configurations on developers.linkedin.com . You just go to MyApps > Create application :
- Add a package name and package hash under Mobile section of your app dashboard on linkedin :
To generate the packageHash code, execute the following code under your MainActivity’s onCreate:
try { PackageInfo info = getPackageManager().getPackageInfo( "pragmatictheories.androidprojects.com.authenticationSample", PackageManager.GET_SIGNATURES); for (Signature signature : info.signatures) { MessageDigest md = MessageDigest.getInstance("SHA"); md.update(signature.toByteArray()); Log.d("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT)); } } catch (PackageManager.NameNotFoundException e) { Log.d("Error", e.getMessage(), e); } catch (NoSuchAlgorithmException e) { Log.d("Error", e.getMessage(), e); }
- Check reading email adress permission under Authentication tab:
User signup
After jumping to SignupActivity, we’ll go through the simple code lines in MainActivity.java where we’ll set navigation to signin and signup uis, and execute the code that logs our packageHash:
public class MainActivity extends Activity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // called only once to generate package hashKey for Linkedin app generateHashkey(); /** if user is logged in --> homeActivity**/ if(FirebaseAuth.getInstance().getCurrentUser()!=null){ startActivity(new Intent(getApplicationContext(), HomeActivity.class)); } } /*** login and signup buttons clicks ***/ @Override public void onClick(View v) { switch (v.getId()){ case(R.id.loginBtn): startActivity(new Intent(getApplicationContext(),LoginActivity.class)); break; case (R.id.signupBtn): startActivity(new Intent(getApplicationContext(),SignupActivity.class)); } } /** for calligraphy lib usage **/ @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); } /** needs to get called only once to get the package hash for Linkedin application **/ public void generateHashkey(){ try { PackageInfo info = getPackageManager().getPackageInfo( "pragmatictheories.androidprojects.com.authenticationSample", PackageManager.GET_SIGNATURES); for (Signature signature : info.signatures) { MessageDigest md = MessageDigest.getInstance("SHA"); md.update(signature.toByteArray()); Log.d("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT)); } } catch (PackageManager.NameNotFoundException e) { Log.d("Error", e.getMessage(), e); } catch (NoSuchAlgorithmException e) { Log.d("Error", e.getMessage(), e); } } }
In SignupActivity.java we’ll add a signUpWithLinkedin(View v) method in which we’ll
- define you API call url defining which field you need
String url = "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,picture-url,email-address)";
- initialize connection to linkedin api
final APIHelper apiHelper = APIHelper.getInstance(getApplicationContext()); apiHelper.getRequest(this, url, new ApiListener() { @Override public void onApiSuccess(ApiResponse apiResponse) { // do something // in this case: create User object from the linkedin profile with } @Override public void onApiError(LIApiError liApiError) { // do something } });
- manage api response
LISessionManager.getInstance(getApplicationContext()).init(this, buildScope(), new AuthListener() { @Override public void onAuthSuccess() { // do something } @Override public void onAuthError(LIAuthError error) { // do something } }, true);
So final content of SignupActivity.java would be the following ( noting that Statics.signUp is a method that perform firebase user registration with the user info we retreived from the API. Firebase registration is out of the scope of this tutorial, you can check it in this tutorial. To continue working at this level, here is the Statics.java class code ) :
public class SignupActivity extends Activity { private User userFromLinkedIn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_signup); } /** Sign up with linkedin **/ public void signUpWithLinkedin(View v){ String url = "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,picture-url,email-address)"; // initializing connection to linkedin api final APIHelper apiHelper = APIHelper.getInstance(getApplicationContext()); apiHelper.getRequest(this, url, new ApiListener() { @Override public void onApiSuccess(ApiResponse apiResponse) { //Toast.makeText(getApplicationContext(), "api success", Toast.LENGTH_LONG).show(); /** create User object from the linkedin profile**/ Gson gson = new Gson(); userFromLinkedIn = gson.fromJson(apiResponse.getResponseDataAsJson().toString(),User.class); } @Override public void onApiError(LIApiError liApiError) { Toast.makeText(getApplicationContext(), liApiError.getMessage(), Toast.LENGTH_LONG).show(); } }); // managing api response LISessionManager.getInstance(getApplicationContext()).init(this, buildScope(), new AuthListener() { @Override public void onAuthSuccess() { //Toast.makeText(getApplicationContext(), "auth succeded ", Toast.LENGTH_LONG).show(); /** signup to firebase with that user **/ Statics.signUp(userFromLinkedIn.getEmailAddress(),userFromLinkedIn.getId(),userFromLinkedIn.getFirstName()+" "+userFromLinkedIn.getLastName(),userFromLinkedIn.getPictureUrl(),SignupActivity.this); } @Override public void onAuthError(LIAuthError error) { //Toast.makeText(getApplicationContext(), "failed " + error.toString(), Toast.LENGTH_LONG).show(); } }, true); } // asking for permission to get Linkedin profile data private static Scope buildScope() { return Scope.build(Scope.R_BASICPROFILE, Scope.R_EMAILADDRESS); } /** onActivityResult **/ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); LISessionManager.getInstance(getApplicationContext()) .onActivityResult(this,requestCode, resultCode, data); } /** for calligraphy lib usage **/ @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); } }
User signin
Now we’ll practically do the same job with the API, we’ll just have call Statics.signIn to use FirebaseAuth.getInstance().signInWithEmailAndPassword() to check if user is registred and log them in :
public class LoginActivity extends Activity { private AccessTokenTracker mAccessTokenTracker; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); } /** Linkedin login **/ public void loginWithLinkedin(View v){ // initializing connection to linkedin api LISessionManager.getInstance(getApplicationContext()).init(this, buildScope(), new AuthListener() { @Override public void onAuthSuccess() { // Toast.makeText(getApplicationContext(), "auth succes", Toast.LENGTH_LONG).show(); } @Override public void onAuthError(LIAuthError error) { //Toast.makeText(getApplicationContext(), " auth failure" + error.toString(), Toast.LENGTH_LONG).show(); } }, true); // managing api responses String url = "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,picture-url,email-address)"; final APIHelper apiHelper = APIHelper.getInstance(getApplicationContext()); apiHelper.getRequest(this, url, new ApiListener() { @Override public void onApiSuccess(ApiResponse apiResponse) { // create User object from the linkedin profile Gson gson = new Gson(); final User userFromLinkedIn = gson.fromJson(apiResponse.getResponseDataAsJson().toString(),User.class); // login to firebase with that user Statics.signIn(userFromLinkedIn.getEmailAddress(), userFromLinkedIn.getId(),LoginActivity.this); } @Override public void onApiError(LIApiError liApiError) { // Toast.makeText(getApplicationContext(), "cant connect to linkedin" + error.toString(), Toast.LENGTH_LONG).show(); } }); } // asking for linkedin account info retreive permission private static Scope buildScope() { return Scope.build(Scope.R_BASICPROFILE, Scope.R_EMAILADDRESS); } /** onActivityResult **/ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); LISessionManager.getInstance(getApplicationContext()) .onActivityResult(this, requestCode, resultCode, data); if(!(FirebaseAuth.getInstance().getCurrentUser()==null)) startActivity(new Intent(LoginActivity.this, HomeActivity.class)); } /** for calligraphy lib usage **/ @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); } }
That’s all practically, Linkedin SDK for Android is so easy to use. I recommand you check out source code of this tutorial here.
Do not hesitate to comment below if any questions or issues pops up.
Recent Comments