Skip to content

Commit

Permalink
implement SocialConnect first iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
VictorAlbertos committed Aug 14, 2020
1 parent 2586868 commit 759be68
Show file tree
Hide file tree
Showing 34 changed files with 1,098 additions and 18 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@
/captures
.externalNativeBuild
.cxx
.build
app/src/main/java/cookpad/com/sample/Credentials.kt
128 changes: 128 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# SocialConnect
SocialConnect simplifies the process of retrieving OAuth tokens from multiple social networks on Android by leveraging the [Navigation component](https://developer.android.com/guide/navigation/navigation-getting-started). This library has as many providers as [ScribeJava](https://github.com/scribejava/scribejava) has, as SocialConnect is built on top of it.

## Setup
Add the JitPack repository in your build.gradle (top level module):
```gradle
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}
```

Apply the SafeArgs plugin ([see how](https://developer.android.com/guide/navigation/navigation-pass-data)) and add next dependency in the build.gradle of your app module:
```gradle
dependencies {
compile 'com.github.cookpad:SocialConnect:0.0.3'
}
```

## Usage
`ConnectFragment` is the entry point of SocialConnect library. To use it, add the `connect_graph` as a destination to your nav graph file, as follow:

```xml
<fragment
android:id="@+id/yourFrgment"
android:name=".YourFragment"
tools:layout="@layout/your_fragment">
<action
android:id="@+id/action_yourFragment_to_connectFragment"
app:destination="@id/connect_graph">
<argument
android:name="serviceConfig"
app:argType="cookpad.com.socialconnect.OAuthServiceConfig" />
<argument
android:name="keyRequestCode"
app:argType="string" />
</action>
</fragment>
```

This will generate `YourFragmentDirections.actionConnectionsFragmentToConnectFragment` which expects an `OAuthServiceConfig` instance and provides the `NavDirection` to access `ConnectFragment` from your nav graph.

OAuth1 with Twitter provider:

```kotlin
findNavController().navigate(
ConnectionsFragmentDirections.actionConnectionsFragmentToConnectFragment(
keyRequestCode = RESULT_CONNECTION_TWITTER,
serviceConfig = OAuth10ServiceConfig(
apiKey = API_KEY_TWITTER,
apiSecret = API_SECRET,
callback = CALLBACK_URL,
clazz = TwitterApi::class.java
)
)
)
```

OAuth2 with Github provider:

```kotlin
findNavController().navigate(
ConnectionsFragmentDirections.actionConnectionsFragmentToConnectFragment(
keyRequestCode = RESULT_CONNECTION_GITHUB,
serviceConfig = OAuth20ServiceConfig(
apiKey = API_KEY_GITHUB,
apiSecret = API_SECRET_GITHUB,
callback = CALLBACK_URL,
clazz = GitHubApi::class.java
)
)
)
```

To retrieve the `Token` back, listen for changes on `findNavController().currentBackStackEntry?.savedStateHandle` expecting a type of `ConnectResult`: ([see](https://developer.android.com/guide/navigation/navigation-programmatic) for more info about how retrieve a result to the previous Destination with the navigation Component)

```kotlin
findNavController().currentBackStackEntry?.savedStateHandle
?.getLiveData<ConnectResult>(RESULT_CONNECTION_TWITTER)
?.observe(viewLifecycleOwner, Observer { connectResult ->
processConnectResult(nameProvider = "Twitter", connectResult = connectResult)
})

findNavController().currentBackStackEntry?.savedStateHandle
?.getLiveData<ConnectResult>(RESULT_CONNECTION_GITHUB)
?.observe(viewLifecycleOwner, Observer { connectResult ->
processConnectResult(nameProvider = "Github", connectResult = connectResult)
})


private fun processConnectResult(nameProvider: String, connectResult: ConnectResult) {
when (connectResult) {
is ConnectResultOk -> {
val token = connectResult.token
val message = when (token) {
is OAuth1AccessToken -> "Provider: $nameProvider, Token: ${token.token} Secret:${token.tokenSecret}"
is OAuth2AccessToken -> "Provider: $nameProvider, AccessToken: ${token.accessToken}"
else -> throw IllegalStateException(token::class.java.canonicalName)
}
Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show()
}
is ConnectResultError -> {
Toast.makeText(requireContext(), connectResult.error.message, Toast.LENGTH_LONG).show()
}
}
}
```

## Sample app
Check the `:app` Gradle module for a showcase of Twitter and Github providers. But prior to build the module, you need to provide the `app/src/main/java/cookpad/com/sample/Credentials.kt` file with the credentials of both your [Twitter](https://developer.twitter.com/en/apps) and your [Github](https://docs.github.com/en/developers/apps/creating-a-github-app) app:

```kotlin
const val API_KEY_TWITTER = ""
const val API_SECRET = ""

const val API_KEY_GITHUB = ""
const val API_SECRET_GITHUB = ""

const val CALLBACK_URL = ""
```

## Proguard
Proguard is already handled via the `consumer-rules.pro` config file.


## Credits
Oauth core authentication: [ScribeJava](https://github.com/scribejava/scribejava)
16 changes: 9 additions & 7 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: "androidx.navigation.safeargs.kotlin"

android {
compileSdkVersion 29
buildToolsVersion "30.0.0"

defaultConfig {
applicationId "cookpad.com.socialconnect"
applicationId "cookpad.com.sample"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
Expand All @@ -25,12 +26,13 @@ android {
}

dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation project(path: ':social-connect')

implementation 'androidx.navigation:navigation-fragment:2.3.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'

implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

implementation 'androidx.appcompat:appcompat:1.2.0'
}
2 changes: 2 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

-keep class * extends androidx.fragment.app.Fragment{}
11 changes: 9 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cookpad.com.socialconnect">
package="cookpad.com.sample">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" />
android:theme="@style/AppTheme">
<activity android:name=".StartActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
88 changes: 88 additions & 0 deletions app/src/main/java/cookpad/com/sample/ConnectionsFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package cookpad.com.sample

import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import com.github.scribejava.apis.GitHubApi
import com.github.scribejava.apis.TwitterApi
import com.github.scribejava.core.model.OAuth1AccessToken
import com.github.scribejava.core.model.OAuth2AccessToken
import cookpad.com.socialconnect.ConnectResult
import cookpad.com.socialconnect.ConnectResultError
import cookpad.com.socialconnect.ConnectResultOk
import cookpad.com.socialconnect.OAuth10ServiceConfig
import cookpad.com.socialconnect.OAuth20ServiceConfig
import kotlinx.android.synthetic.main.connections_fragment.bt_github
import kotlinx.android.synthetic.main.connections_fragment.bt_twitter

class ConnectionsFragment : Fragment(R.layout.connections_fragment) {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

bt_twitter.setOnClickListener {
findNavController().navigate(
ConnectionsFragmentDirections.actionConnectionsFragmentToConnectFragment(
keyRequestCode = RESULT_CONNECTION_TWITTER,
serviceConfig = OAuth10ServiceConfig(
apiKey = API_KEY_TWITTER,
apiSecret = API_SECRET,
callback = CALLBACK_URL,
clazz = TwitterApi::class.java
)
)
)
}

bt_github.setOnClickListener {
findNavController().navigate(
ConnectionsFragmentDirections.actionConnectionsFragmentToConnectFragment(
keyRequestCode = RESULT_CONNECTION_GITHUB,
serviceConfig = OAuth20ServiceConfig(
apiKey = API_KEY_GITHUB,
apiSecret = API_SECRET_GITHUB,
callback = CALLBACK_URL,
clazz = GitHubApi::class.java
)
)
)
}

findNavController().currentBackStackEntry?.savedStateHandle
?.getLiveData<ConnectResult>(RESULT_CONNECTION_TWITTER)
?.observe(viewLifecycleOwner, Observer { connectResult ->
processConnectResult(nameProvider = "Twitter", connectResult = connectResult)
})

findNavController().currentBackStackEntry?.savedStateHandle
?.getLiveData<ConnectResult>(RESULT_CONNECTION_GITHUB)
?.observe(viewLifecycleOwner, Observer { connectResult ->
processConnectResult(nameProvider = "Github", connectResult = connectResult)
})
}

private fun processConnectResult(nameProvider: String, connectResult: ConnectResult) {
when (connectResult) {
is ConnectResultOk -> {
val token = connectResult.token
val message = when (token) {
is OAuth1AccessToken -> "Provider: $nameProvider, Token: ${token.token} Secret:${token.tokenSecret}"
is OAuth2AccessToken -> "Provider: $nameProvider, AccessToken: ${token.accessToken}"
else -> throw IllegalStateException(token::class.java.canonicalName)
}
Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show()
}
is ConnectResultError -> {
Toast.makeText(requireContext(), connectResult.error.message, Toast.LENGTH_LONG).show()
}
}
}

companion object {
const val RESULT_CONNECTION_TWITTER = "result_connection_twitter"
const val RESULT_CONNECTION_GITHUB = "result_connection_github"
}
}
5 changes: 5 additions & 0 deletions app/src/main/java/cookpad/com/sample/StartActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package cookpad.com.sample

import androidx.appcompat.app.AppCompatActivity

class StartActivity : AppCompatActivity(R.layout.start_activity)
26 changes: 26 additions & 0 deletions app/src/main/res/layout/connections_fragment.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:fitsSystemWindows="true"
android:orientation="vertical">

<Button
android:id="@+id/bt_twitter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/colorPrimary"
android:text="@string/twitter_connect"
android:textColor="@color/colorWhite" />

<Button
android:id="@+id/bt_github"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:backgroundTint="@color/colorPrimary"
android:text="@string/github_connect"
android:textColor="@color/colorWhite" />

</LinearLayout>
16 changes: 16 additions & 0 deletions app/src/main/res/layout/start_activity.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".StartActivity">

<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</FrameLayout>
26 changes: 26 additions & 0 deletions app/src/main/res/navigation/nav_graph.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/connectionsFragment">

<include app:graph="@navigation/connect_graph" />

<fragment
android:id="@+id/connectionsFragment"
android:name="cookpad.com.sample.ConnectionsFragment"
tools:layout="@layout/connections_fragment">
<action
android:id="@+id/action_connectionsFragment_to_connectFragment"
app:destination="@id/connect_graph">
<argument
android:name="serviceConfig"
app:argType="cookpad.com.socialconnect.OAuthServiceConfig" />
<argument
android:name="keyRequestCode"
app:argType="string" />
</action>
</fragment>

</navigation>
7 changes: 4 additions & 3 deletions app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
<color name="colorPrimary">#FF9933</color>
<color name="colorPrimaryDark">#CC7A29</color>
<color name="colorAccent">#8BAD00</color>
<color name="colorWhite">#ffffff</color>
</resources>
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<resources>
<string name="app_name">SocialConnect</string>
<string name="twitter_connect">Connect with Twitter</string>
<string name="github_connect">Connect with Github</string>
</resources>
Loading

0 comments on commit 759be68

Please sign in to comment.