SocialApi SDK Wrappers - B4A Single-Sign-On with multiple providers

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User
SocialApi version 2.51 requires B4A 3.80
Latest package

SocialApi wrapper, sdks, providers and samples
https://www.dropbox.com/s/8xgnbegugs3gtdq/socialapi.zip

Introduction

As already seen in many android apps, the use of facebook or google+ connectivity it is a very common practice. This will show you how to properly incorporate a b4a single-sign-on (SSO) using multilple socialapi providers.

It is assumed that you have already completed at least one of the following how-to-use-a-specific-provider tutorials:

Available SocialApiProvider classes:
  • FacebookProvider: A non activity object that can only be declared in any Sub Process_Globals.
  • GooglePlusProvider: A non activity object that can only be declared in any Sub Process_Globals.
  • TwitterProvider: A non activity object that can only be declared in any Sub Process_Globals.
  • InstagramProvider: A non activity object that can only be declared in any Sub Process_Globals
  • VkProvider: A non activity object that can only be declared in any Sub Process_Globals
  • SocialApiActivity: An activity object that can be only declared in a Sub Globals and is used to bind all SocialApiProvider objects to a single SocialApiActivity through the SocialApiActivity.BindWithEvent method.
Getting started
  1. Download the latest socialapi package and extract its contents anywhere on your hard disk and note the folder name.
  2. Copy the wrapper files (jar + xml) in the socialapi folder into your B4A Libraries folder
  3. Open the socialapi\multiple\sample1 project. The sample has AdditionalRes and AdditionalJar directives that have to be changed. Change the C:\b4a-dev folder to where you have previously extracted the socialapi package.
The socialapi\multiple\samples folder contains:
  • Sample1: Quick single connect sample that can be used as a bare-bone template for your new apps
  • Sample2: Using and maintaining 2 active providers on the same activity

Download the precompiled sample1 APK
Download the precompiled sample2 APK



upload_2014-7-2_21-11-19.png
upload_2014-7-9_11-38-40.png

upload_2014-7-2_21-8-14.png
upload_2014-7-2_21-8-26.png
upload_2014-7-4_16-8-8.png
upload_2014-7-5_20-25-2.png



Building a single social connect app using all providers (Sample1)

This sample is based on subclassing. In short, subclassing is a method in which we have a base object that defines a set of properties and methods, and classes that extend/inherit/override it.

In our case, we have a base class SocialApiProvider that exposes several properties and methods and all providers (such as FacebookProvider, GoogleProvider etc) inherit them.

For example, if we get an event raised by a Provider (FacebookProvider), we can cast the Sender object.
B4X:
Dim Provider As SocialApiProvider = Social.ActiveProvider 'Casting
Calling the base class Me property will result in calling FacebookProvider.Me
B4X:
Log(Provider.Me) 'Will call FacebookProvider.Me
As we will see in our sample below, the most useful base properties and methods of our SocialApiProvider class are:
  • Properties: Me, User, Connected, Ready
  • Methods: Login, Logout, Deauthorize, Retry
You can also check if a base SocialApiProvider object is a specific type and call its methods.
B4X:
If (Provider is FacebookProvider)
    Dim Facebook as FacebookProvider = Provider
    Facebook.RequestPublishPermissions
End If

Now, lets go through the sample step-by-step.

1. Create a new folder in your app root folder named AppConfig\Values. In there, create a new file named strings.xml and add your facebook app details (app_name and app_id):
B4X:
<resources>
    <string name="app_id"><your_app_id></string>
    <string name="app_name"><your_app_name></string>
</resources>


2. Add following code to your manifest:
B4X:
AddApplicationText(
    <meta-data
        android:name="com.facebook.sdk.ApplicationId"
        android:value="@string/app_id"/>
      <activity
        android:name="com.facebook.LoginActivity"
        android:theme="@android:style/Theme.Translucent.NoTitleBar"
        android:label="@string/app_name"/>)

AddApplicationText(
    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />)

AddApplicationText(
      <activity
        android:name="com.datasteam.twitter.android.TwitterActivity"
        android:theme="@android:style/Theme.Translucent.NoTitleBar"/>)

AddApplicationText(
      <activity
        android:name="com.datasteam.instagram.android.InstagramActivity"
        android:theme="@android:style/Theme.Translucent.NoTitleBar"/>)

AddApplicationText(
    <activity
        android:name="com.vk.sdk.VKOpenAuthActivity" />)


3. Add following directives to your project's main file:
B4X:
'FACEBOOK related directives
#AdditionalRes: ..\AppConfig
#AdditionalRes: <your-installation-folder>\socialapi\facebook\sdk\res
#AdditionalJar: <your-installation-folder>\socialapi\facebook\sdk\facebooksdk.jar

'GOOGLE+ related directives
#AdditionalRes: <your-installation-folder>\socialapi\googleplus\sdk\res, com.google.android.gms
#AdditionalJar: <your-installation-folder>\socialapi\googleplus\sdk\gplussdk.jar

'Twitter related directives
#AdditionalRes: <your-installation-folder>\socialapi\twitter\sdk\res
#AdditionalJar: <your-installation-folder>\socialapi\twitter\sdk\twittersdk.jar

'Instagram related directives
#AdditionalRes: <your-installation-folder>\socialapi\instagram\sdk\res
#AdditionalJar: <your-installation-folder>\socialapi\instagram\sdk\instagramsdk.jar

'Vk.com related directives
#AdditionalRes: <your-installation-folder>\socialapi\vk\sdk\res, com.vk.sdk
#AdditionalJar: <your-installation-folder>\socialapi\vk\sdk\vksdk.jar


4. Select the SocialApi library from the list of the available libraries in the IDE.

5. In the Social code module, we define all our available providers and add them in a global array
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

    Dim Facebook As FacebookProvider
    Dim GooglePlus As GooglePlusProvider
    Dim Twitter As TwitterProvider : Twitter.Initialize("<your-consumer-key>", "<your-consumer-secret>")
    Dim Instagram As InstagramProvider : Instagram.Initialize("<your-client-id>","<your-client-secret>","<your-callback-url>")
    Dim Vk As VkProvider : Vk.Initialize("<your-app-id>")

    'Add all providers to a global array to be used by verious functions in other modules/activities
    Dim Providers() As SocialApiProvider = Array As SocialApiProvider (Facebook, GooglePlus, Twitter, Instagram, Vk)
End Sub


6. In the Social code module, we built a function that will return the currently active (connected) provider
B4X:
Sub ActiveProvider As SocialApiProvider
    'Traverse the providers array and find the already connected provider if any
    For i=0 To Providers.Length-1
        If Providers(i).Connected Then
            Return Providers(i)
        End If
    Next
    Return Null
End Sub


7. In the Main activity module, we define a local SocialApiActivity object that will be used in the Sub Activity_Resume to bind our array of providers to it and set the event prefix

B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.

    Dim ThisActivity As SocialApiActivity
End Sub

Sub Activity_Resume
    ThisActivity.InitializeAndBind(Social.Providers, "provider")
End Sub


8. In the Main activity module, we define the events that will be raised
B4X:
Sub Provider_Event (Provider As SocialApiProvider)
    'Since this event will be raised by all providers, we don't want to process events
    'from other providers if we are already connected
    If Social.ActiveProvider <> Null AND Social.ActiveProvider <> Provider Then Return

    BtnConnect.Enabled = Not(Provider.Connected)
    BtnDisconnect.Enabled = Provider.Connected
    BtnDeAuthorize.Enabled = Provider.Connected

    PnlActions.Visible = Provider.Connected AND Provider.Ready

    LbConnectedWith.Text = Provider.Type.ToLowerCase
    LbConnectedWith.TextColor = IIF(Provider Is FacebookProvider, Colors.Blue, Colors.Red)
    BtnAction.Text = Provider.Type.ToLowerCase & " provider specific call"
    LbUserName.Text = Provider.User.Name
End Sub
B4X:
Sub Provider_Connected (Provider As SocialApiProvider)
    Msgbox("Welcome " & Provider.User.Name, Provider.Type & ": JustConnected!")
End Sub

Sub Provider_Disconnected (Provider As SocialApiProvider)
    Msgbox("Bye bye!", Provider.Type & ": JustDisconnected!")
End Sub

Sub Provider_Failed (Provider As SocialApiProvider)
    If Msgbox2("Provider '" & Provider.Type & "' failed to actualize your details."&CRLF&CRLF&"Retry?", Provider.Type & ": Error", "Yes", "No", "", Null) = DialogResponse.POSITIVE Then
        Provider.Retry
    End If
End Sub

10. In the Main activity module, we built out login/logout/deauthorize functions. Note that these functions are Provider type agnostic and access it through the base class type.
B4X:
Sub BtnConnect_Click
    StartActivity(ConnectWith)
End Sub

Sub BtnDisconnect_Click
    Social.ActiveProvider.Logout
End Sub

Sub BtnDeAuthorize_Click
    Social.ActiveProvider.DeAuthorize
End Sub


11. In the ConnectWith activity module, we define a local SocialApiActivity object and bind it to our global providers array setting an event for handling any state updates
B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.

    Dim ThisActivity As SocialApiActivity
End Sub

Sub Activity_Resume
    ThisActivity.InitializeAndBind(Social.Providers, "provider")
End Sub


12. In the ConnectWith activity module, we define the Provider_Connected that will handle the connected state and will inform our Main activity module
B4X:
Sub Provider_Connected (Provider As SocialApiProvider)
    CallSubDelayed2(Main, "Provider_Connected", Provider)
    Activity.Finish
End Sub


13. In the ConnectWitn activity module, we build our login-with handlers
B4X:
Sub BtnConnectWithFacebook_Click
    Social.Facebook.Login(Null)
End Sub

Sub BtnConnectWithGooglePlus_Click
    Social.GooglePlus.Login
End Sub

Sub BtnConnectWithTwitter_Click
    Social.Twitter.Login(true)
End Sub

Sub BtnConnectWithInstagram_Click
    Social.Instagram.Login
End Sub

Sub BtnConnectWithVk_Click
    Social.Vk.Login(null)
End Sub


14. In the Main activity module, we built some testing functions in which we will call functions of t he active provider in both abstract and type specific way
B4X:
Sub BtnUser_Click
    Msgbox(Social.ActiveProvider.User, "User: " & Social.ActiveProvider.Type)
End Sub

Sub BtnMe_Click
    Msgbox(Social.ActiveProvider.Me, "Me: " & Social.ActiveProvider.Type)
End Sub

Sub BtnAction_Click
    Dim Provider As SocialApiProvider = Social.ActiveProvider

    If (Provider Is FacebookProvider) Then
        Dim Facebook As FacebookProvider = Provider
        Facebook.RequestPublishPermissions
    End If

    If (Provider Is GooglePlusProvider) Then
        Dim GooglePlus As GooglePlusProvider = Provider
        Msgbox(GooglePlus.GetPeopleVisible, "GooglePlus.GetPeopleVisible")
    End If

    If (Provider Is TwitterProvider) Then
        Dim Twitter As TwitterProvider = Provider
        Msgbox(Twitter.GetHomeTimeline(5,0,0), "Twitter.GetHomeTimeline")
    End If

    If (Provider Is InstagramProvider) Then
        Dim Instagram As InstagramProvider = Provider
        Msgbox(Instagram.GetFeed(10), "Instagram.GetFeed")
    End If

    If (Provider Is VkProvider) Then
        Dim Vk As VkProvider = Provider
        Msgbox(Vk.GetMe(Array As String(Vk.Constants.UserFields.BDATE)), "Vk.GetMe")
    End If
End Sub

Please test and post any feedback, questions, comments you may have!
That's all for now folks!~ :D

Version history


2.51
  • [SocialApi] Fixed: Map object fixes that prevented proper access to Result.Map
  • [VkProvider] Added: Login permissions scopes: VkProvider.Login(Array as String(VkProvider.Constants.Permissions.FRIENDS))
  • [TwitterProvider] Added: Force always ask credentials parameter (boolean) in method TwitterProvider.Login
2.5

  • [SocialApi] Added: VkProvider (initial version)
2.41
  • [GooglePlusProvider] Fixed: Instead of a disconnect event, a connect event was fired.
2.4
  • [SocialApi] Added: BaseResult
  • [SocialApi] Changed: All provider results are now derived from BaseResult
  • [SocialApiProvider] Renamed: GetWithEvent to Initialize and BindWithEvent to InitializeAndBind
  • [SocialApiProvider] Removed: JustConnected, JustDisconnected, Failed properties
  • [SocialApiProvider] Added: Provider_Connected,Provider_Disconnected, Provider_Failed events and Ready property
  • [SocialApiProvider] Added: Upload method
  • [GooglePlusProvider] Changed: All calls return GoogleResult instead of Map which is derived from BaseResult
  • Added sample2 in socialapi\multiple\samples
  • Updated all samples with the new events
2.32
  • [sdk] Update: Optimized login flow on all sdks. Please update.
  • [SocialApi] Renamed: BaseProvider.User.Uid to BaseProvider.User.Id
  • [TwitterProvider] Changed: GetHomeTimeline to GetTimeline(int UserId)
  • [TwitterProvider] Added: GetFollowers, GetFriends
  • All samples updated.
2.31
  • [FacebookProvider] Added: HasPermission method.
2.3
  • Restructured again into a single package after finding out how to properly use the #AdditionalRes directive to avoid conflict with other b4a libraries
  • [SocialApi] Added: InstagramProvider
  • [TwitterProvider] Added: TweetWithMedia method. You can now tweet with an attached file!
  • [TwitterProvider] Added: Search method.
  • [InstagramProvider] Added: Search method.
2.2
  • Restructured all packages due to a conflict with AdMod library. Now, every provider has its own package
2.1
  • [SocialApi] Added: TwitterProvider
2.0
  • Migrated all existing wrappers into a single library
1.0
  • Initial version
 
Last edited:

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User
Update: 2.2
  • Restructured all packages due to a conflict with AdMod library. Now, every provider has its own package. Please read the "Getting started" for updated installation instructions!
 
Last edited:

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User
Update: 2.3
  • Restructured again into a single package after finding out how to properly use the #AdditionalRes directive to avoid conflict with other b4a libraries (ie AdMob)
  • Added: InstagramProvider
Provider specific changes

TwitterProvider

  • Added: TweetWithMedia method. You can now tweet with an attached file!
  • Added: Search method.
InstagramProvider:
  • Added: Search method.
Important notes

Please update the sdks and the wrapper from the socialapi package and delete FacebookProvider, GooglePlusProvider, TwitterProvider and InstagramProvider jar+xml files from your B4A libs folder. Consult the Getting Started section for installation instructions

GooglePlusProvider users should update the #AdditionalRes directive as shown below:
B4X:
    #AdditionalRes: C:\b4a-dev\socialapi\googleplus\sdk\res, com.google.android.gms
 
Last edited:

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User
Update: 2.32
  • [sdk] Update: Optimized login flow on all sdks. Please update.
  • [SocialApi] Renamed: BaseProvider.User.Uid to BaseProvider.User.Id
  • [TwitterProvider] Changed: GetHomeTimeline to GetTimeline(int UserId)
  • [TwitterProvider] Added: GetFollowers, GetFriends
  • All samples and tutorials updated.
 

brelto85

Active Member
Licensed User
Longtime User
hi
i've implemented this solution with social module that provides the social wrapper
i've two problems:

1. The Facebook login works correctly but the Logout method doesn't fire the JustDisconnect event. Follow below the code of my activity:

B4X:
Sub Activity_Resume
    ThisActivity.BindWithEvent(Social.Providers, "provider_event")
End Sub

B4X:
Sub SWFb_CheckedChange(Checked As Boolean)
    If Social.Facebook.Connected AND Checked Then Return
    If Checked Then
        Social.Facebook.Login(Null)
    Else
        Social.Facebook.Logout
    End If
End Sub

B4X:
Sub Provider_JustConnected (Provider As SocialApiProvider)
    Dim Provider As SocialApiProvider = Social.ActiveProvider

    If (Provider Is FacebookProvider) Then
        Social.Facebook.RequestPublishPermissions
    End If
End Sub

Sub Provider_JustDisconnected (Provider As SocialApiProvider)
    ToastMessageShow("Disconnessione da " & Provider.Type & " avvenuta con successo", True)
End Sub

Sub Provider_Retry (Provider As SocialApiProvider)
End Sub

Sub provider_event
    Dim Provider As SocialApiProvider = Sender

    Social.CheckConnectionState(Provider)
  
    If Not(Provider.Connected) AND Social.Connected Then Return

    If Provider.Failed Then
        CallSubDelayed2(Me, "Provider_Retry", Provider)
    End If
  
    SWFb.Checked = Social.Facebook.Connected
    SWTw.Checked = Social.Twitter.Connected
End Sub

2. The twitter login not works correctly.

The "Allow this application to be used to Sign in with Twitter" option is flagged in Twitter developer console
 

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User
First of all, let me suggest few things.

The purpose of the abstraction of the BaseProvider is to access the active provider through the Social.ActiveProvider and Social.ActiveProvider.Me/Social.ActiveProvider.User properties. Only when explicitly required, you can cast the Social.ActiveProvider to a specific Provider and make a function call. The less calls to FacebookProvider, TwitterProvider objects, the better.

The correct usage is to have 1 login handler that will invoke the ConnectWith activity and 1 logout handler that will call the abstract Social.ActiveProvider.Logout. That means you don't have to handle with provider specific calls. This will eliminate the need for Login/Logout buttons for each provider that your app has.

B4X:
Sub BtnConnect_Click
    StartActivity(ConnectWith)
End Sub

Sub BtnDisconnect_Click
    Social.ActiveProvider.Logout  
End Sub

I also tested the sample1 in the multiple folder and the event is raised properly. Does the sample1 works for you? What are the differences with your code?

Also, what to you mean "The twitter login not works correctly"? Have you downloaded the latest socialapi package? Have you updated your code with the correct paths and sdks as illustrated in the "Getting started" section?
 
Last edited:

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User
Just to understand your code.

I assume that you don't have a ConnectWith activity, you have a Social code module (an exact copy of the Social code module of the sample with a Facebook and Twitter provider) and 2 connect-with buttons (Facebook, Twitter) in your main activity, right?
 

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User

brelto85

Active Member
Licensed User
Longtime User
consider that i use your library not to login but to connect the user with yours social and allow to share some picture or post in a second time
I've a preference activity with n switch button like the attached image
 

Attachments

  • 2014-07-07_23-34-11.png
    2014-07-07_23-34-11.png
    62.1 KB · Views: 435
Top