Cette conférence vous expliquera en détail pourquoi mettre en place cette authentification et surtout comment la mettre en place.
Vous découvrirez ainsi:
la console des GoogleService,
comment utiliser l’objet PlusClient et ConnectionResult pour gérer l’identification de votre utilisateur,
comment mettre en place la « magic connexion » et la « manual connexion »,
comment mettre en place cette authentification au sein du cycle de vie de votre application,
comment charger le graphe social de l’utilisateur, faire des posts interactifs et des « application activities »…
Un grand moment pour tous ceux qui se demandent encore quelle est la meilleure stratégie pour authentifier son utilisateur.
Cette conférence s’associe:
d’un tutorial que vous pouvez retrouver sur GitHub: SignInWithGoogleTutorial(https://github.com/MathiasSeguy-Android2EE/SignInWithGoogleTutorial) sur GitHub.
d’une application mettant en place cette authentification que vous pouvez retrouver sur GooglePlay: MyPublicGoogleProfile (https://play.google.com/store/apps/details?id=com.android2ee.project.gplus.signin.publicid&hl=fr).
Et bien sûr la conférence va être disponible sur Android2EE dès le Vendredi 20 au rayon OpenResource\Conférences.
Vous aussi, authentifiez vos utilisateurs, inter-agissez avec eux et simplifiez leur la vie:
En espérant que vous y découvrirez votre bonheur :) .
2. Android2EE est référencé en tant qu’organisme de formation, vous pouvez faire prendre en charge tout ou partie
du montant de cette formation par votre OPCA. Cette formation Initiation avancée à Android est éligible au titre
du DIF et CIF.
Lieu : Paris, Toulouse, Lyon
Durée : 3 jours
Prix : 1680 €
Lieu : Paris, Toulouse, Lyon
Durée : 5 jours
Prix : 2980 €
Lieu : Paris, Toulouse, Lyon
Durée : 3 jours
Prix : 1780 €
3. 3
Wes Tarle Lee Denison
And of course thanks to
https://developers.google.com/events/io/sessions/324806378
4. Google+ SignIn Késako ?o?(p7)
Mise en place de l'environnement (p10)
Service Google : Vérifier la présence sur l'appareil
cible(p18)
PlusClient - Principe de connexion(p18)
•OverView (p19)
•Reconnexion Magique(p21)
•Connexion Manuelle(p23)
•Suppression des droits (p24)
•Cycle de vie (p25)
PlusClient - Features(p18)
•Utilisateur (p28)
•Unique Id (p29)
•Graphe Social (p30)
4
Beyond the blue dot (p18):
•Interactives Posts
•Application Activities : So called Moment
Disponible sur Github, SlideShare, GooglePlay et sur
Android2ee
7. Enregistre l'utilisateur pas le device
Sur Android l'utilisateur possède déjà une
identité => pas besoin de mot de passe
Pas besoin de permission !!!
7
OAuth2.0 Authentification encapsulée, masquée
mais présente
Ré-utilisation de cet identification pour accéder
aux autres services Google (via le token OAuth et
l'ajout de scope)
11. 11
Dans OverView, choisissez votre
projectID.
Pas de pression, il doit juste être unique,
un votreNomDePackage.replace(".","-")
devrait suffire.
<-Là
Ce qui donne
12. 12
1. Créez la page GooglePlus de votre projet
2. Associez son identifiant à votre projet
dans les Google Service
3. Dans votre page de projet GooglePlus,
tableau de bord/services connectés
acceptez la connexion
4. Vous pouvez voir vos statistiques <-Là
2
3
4
13. 13
Dans l'onglet Service, Choisissez "Google + API"
Allez dans l'onglet API ACCESS, créez votre "OAuth 2.0 Client ID""
N'oubliez pas d'enregistrer votre clef de Debug et votre clef de Production
<-Là
<-Là
<-Là
<-Là
14. 14
Et voilà, c'est fini pour l'enregistrement de votre projet au sein des services Google.
23. 23
/**
* The PlusClient
*/
private PlusClient mPlusClient;
/**
* The connectionResult returned by the last connection try
*/
private ConnectionResult mConnectionResult;
Activity
24. 24
// Build your GPlus Person:
//First create the builder (Context, connectionCallbacks , connectionFailedListener )
mPlusClient = new PlusClient.Builder(this, this, this)
//Then define/register the AppActivity you want to set possible for that client:
.setVisibleActivities("http://schemas.google.com/AddActivity",
"http://schemas.google.com/CommentActivity",
"http://schemas.google.com/DiscoverActivity")
//AddActivity: This type of app activity is the generic fallback type. Use it when no other app activity type is appropriate.
// DiscoverActivity: Use this type when your user discovers something in your app, such as discovering a new album.
// CommentActivity: Use this type when your user comments on an article, blog entry, or other creative work.
//And so on, the list is here: https://developers.google.com/+/api/moment-types/
// And define your application scope (writeMoment requires the PLUS_LOGIN OAuth 2.0 scope)
.setScopes(
Scopes.PLUS_LOGIN, // for accessing the user's name, basic profile info, list of people in the user's circles, and writing app activities to Google
Scopes.PLUS_PROFILE, // OAuth 2.0 scope for accessing the user's Google+ profile data.
Scopes.APP_STATE, // Scope for using the App State service.
Scopes.GAMES) // Scope for accessing data from Google Play Games.
//And then build the PlusClient
.build();
26. Première connexion
26
Si votre utilisateur s'est déjà connecté et a accordé les droits à l'application, il est en cache.
L'appel à mPlusClient.connect() marche directement.
@Override
protected void onStart() {
super.onStart();
// Ensure calling that method in onStart not in onResume (because onResume is
called to often and to late in the activity life cycle.
if (!mPlusClient.isConnected() && !mPlusClient.isConnecting()) {
mPlusClient.connect();
}
}
Connexions suivantes
27. 27
@Override
public void onConnected(Bundle connectionHint) {
// The PlusClient is build, you can use it
Person accountOwner = mPlusClient.getCurrentPerson();
}
@Override
public void onDisconnected() {
// When using AccessRevoked, this method is never called
// Just disconnect the user, next call on connect, will connect him again
smoothly
// He will have the same account and the same grants as before
// disconnect the user
mPlusClient.disconnect();
// Kill the connectionResult
mConnectionResult = null;
}
28. 28
@Override
public void onConnectionFailed(ConnectionResult result) {
// Store the result (meaning a connexion has been tried)
mConnectionResult = result;
// you want to automagicly display him the solution to its problem
either by showing the native SignIn
// Activity or the createAccount one. It's handle by the google team
throught the GoogleService Api
try {
// if auto-connection failed then ensure to display the SignIn
Activity to the user for him to be able
// to sign in if it's a Sign_In_Required else just try to find a
solution
if (result.hasResolution()) {
result.startResolutionForResult(this,
requestCodeResolverError);
}
} catch (SendIntentException e) {
Log.e(TAG, "onConnectionFailed " + result, e);
}
}
/** * The request code for the Intent connection launch by
startActivityForResult */
private final static int requestCodeResolverError = 12354;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// This method is called when the activity of connection started by
// mConnectionResult.startResolutionForResult(this, requestCodeResolverError); has
finished
// It has displayed the connection activity made by Google Fellow.
if (requestCode == requestCodeResolverError && resultCode == RESULT_OK) {
// hey now you have the rights granted the call to connect will work
mConnectionResult = null;
mPlusClient.connect();
} else {
// ensure the connection is reset, because it has been consume
mConnectionResult = null;
super.onActivityResult(requestCode, resultCode, data);
}
}
30. /** * Called when the SignIn button is hit */
private void gPlusSignInClicked() {
connectionAskedByUser = true;
if (!mPlusClient.isConnected() && !mPlusClient.isConnecting() && mConnectionResult != null) {
// In this case you have already called mPlusClient.connect (because mConnRes!=null) but it failed. So you try to launch the resolution of that failure by calling
startResolution which you should display the G+SignIn flow
try {
mConnectionResult.startResolutionForResult(this, requestCodeResolverError);
} catch (SendIntentException e) {
// It also failed, you' re a lucky guy, today is your day :). So you restart the connection process again.
mConnectionResult = null;
mPlusClient.connect();
signInButton.setEnabled(false);
}
} else if (!mPlusClient.isConnected() && !mPlusClient.isConnecting() && mConnectionResult == null) {
// This case is called when you haven't already try to connect (meaning you don't have the mPlusClient.connect in your onResume or onStart method)
// In our case, we will never go through this code just try to connect
mPlusClient.connect();
signInButton.setEnabled(false);
} else {
// Something forgotten or what ?
}
}
30
31. /** * Called when the SignIn button is hit */
private void gPlusSignInClicked() {
connectionAskedByUser = true;
if (!mPlusClient.isConnected() && !mPlusClient.isConnecting() && mConnectionResult !=
null) {
// In this case you have already called mPlusClient.connect (because mConnRes!=null) but it failed.
So you try to launch the resolution of that failure by calling startResolution which you should
display the G+SignIn flow
try {
mConnectionResult.startResolutionForResult(this, requestCodeResolverError);
} catch (SendIntentException e) {
// It also failed, you' re a lucky guy today. So you restart the connection process again.
mConnectionResult = null;
mPlusClient.connect();
signInButton.setEnabled(false);
}
} else if (!mPlusClient.isConnected() && !mPlusClient.isConnecting() && mConnectionResult
== null) {
// This case is called when you haven't already try to connect (meaning you don't have the
mPlusClient.connect in your onResume or onStart method)
// In our case, we will never go through this code just try to connect
mPlusClient.connect();
signInButton.setEnabled(false);
} else {
// Something forgotten or what ?
}
} 31
@Override
public void onConnectionFailed(ConnectionResult
result) {
// You can just set the mConnectionResult for your
user to be able to connect using the signInButton
// @see gPlusSignInClicked()
if (!connectionAskedByUser) {
// This case is when you want your user to
click the g+connection button to connect
// and not hide it by an automatic
connection
mConnectionResult = result;
} else {
// Usual case : @see slide "Implementing
GooglePlayServicesClient.OnConnectionFaile
dListener"
.....
}
}
33. Just disconnect the user, next call on
connect, will connect him again
smoothly
Give your user the ability to choose an
another account at the next connection
Give your user the ability to reset its grants
for your application
33
private void clear() {
if (mPlusClient.isConnected()) {
mPlusClient.clearDefaultAccount();
// You should call disconnect, else
nothing will happens (an exception
in fact)
// disconnect the user
mPlusClient.disconnect();
// Kill the connectionResult
mConnectionResult = null;
}
}
private void revoke() {
if (mPlusClient.isConnected()) {
mPlusClient.revokeAccessAndDisconnect(new
OnAccessRevokedListener() {
@Override
public void onAccessRevoked(ConnectionResult
status) {
// do a stuff
userAccessRevoked(status);
}
});
}
}
private void disconnect() {
if (mPlusClient.isConnected()) {
// disconnect the user
mPlusClient.disconnect();
// Kill the connectionResult
mConnectionResult = null;}
}
34. 34
Et si j'ai plusieurs Activity dans mon application... comment que je fais pour assurer l'authentification de l'utilisateur quelques soit
la manière dont je rentre dans l'application (backstack pop, onResume, startActivity...)?
Mise en place dans l'objet Application ?
Application doit implémenter la pattern (onConnected, onDisconnected, onConnectionFailed, PlusClient.connect...) dans
onCreate ...
×Fuite mémoire (impossible d'appeler disconnect);
×Complexité de sa mise en place;
×Fausse bonne idée.
35. 35
Et si j'ai plusieurs Activity dans mon application... comment que je fais pour assurer l'authentification de l'utilisateur quelques soit
la manière dont je rentre dans l'application (backstack pop, onResume, startActivity...)?
Mise en place d'une Activity mère qui implémente la connexion et héritage de cette activité par toutes vos activités.
Préconsié par Wes Tarle dans sa conférence
N'est pas centralisé, ne peut être partagé entre les activités, les services,...
36. Stockage dans l'objet Application ?
Application stocke l'instance de PlusClient courante et possède la méthode disconect (qui fait PlusClient.disconnect)
Existence d'une Activity de type GPlusConnectionActivity qui quand elle instancie PlusClient le stocke dans Application;
Chaque Activity vérifie (dans sa méthode onStart) si l'instance de PlusClient est dans Application, s'il n'existe pas lance
l'Activity de connexion: GPlusConnectionActivity
Chaque Activity appèle Application.disconect() dans sa méthode onStop
Pas de duplication de code;
Pas de fuite mémoire;
Workflow simple et compréhensible par tous (développeurs et utilisateurs);
L'objet PlusClient est accessible par tous au sein de l'application (Activity/Service/BroadcastReceiever...)
Peut-être utilisé par vos services.
36
Et si j'ai plusieurs Activity dans mon application... comment que je fais pour assurer l'authentification de l'utilisateur quelques soit
la manière dont je rentre dans l'application (backstack pop, onResume, startActivity...)?
44. 44
On Android device In Browser
ContentTarget
ContentURL
ActionTarget
ContentTarget
ContentURL
ActionTarget
ContentURL: 2 façons de les mettre en place
psBuilder.setContentDeepLinkId(
contentDeepLinkIdUrl, // content_deepl_id_url
contentDeepLinkTitleUrl,// content_deepl_title_url
contentDeepLinkDescUrl,// content_deepl_descr_url
contentDeepLinkThumbURI);// my picture but why ?o?
// The ContentUrl content_url with project page
psBuilder.setContentUrl(Uri.parse(contentUrl));
45. 45
private void sendInteractivePost(String message, String userId) {
PlusShare.Builder psBuilder = new PlusShare.Builder(this, mPlusClient);
// Build the post itself
// The message of the post
psBuilder.setText(message);
// The content url of the post
psBuilder.setContentUrl(Uri.parse(https://plus.google.com/%1$s/about));
// Add the CallToAction
// add_call_uri=https://plus.google.com/%1$s/about
String addCallUri = getString(R.string.add_call_uri, userId);
Uri addCallURI = Uri.parse(addCallUri);
// Set the call to Action
psBuilder.addCallToAction("CONNECT", addCallURI, "user/%1$s?action=see");
// And then drop the moment in your user stream
startActivityForResult(psBuilder.getIntent(), 0);
}
46. 46
public class InteractivePostCallBackActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Retrieve the DeepLink
Uri deepLink = Uri.parse(PlusShare.getDeepLinkId(getIntent()));
// Define the Activity that will be launched
Intent target = new Intent();
if (deepLink.isHierarchical() && deepLink.getPath().startsWith("/user/")) {
// Get extra to better target the activity to launch
target.putExtra("profileId", deepLink.getLastPathSegment());//
// Do the same for parameters
if (deepLink.getQueryParameter("action") != null) {
if (deepLink.getQueryParameter("action").contains("see")) {
target.putExtra("action", "see");
}
}
//Then decide which activity you want to launch
target.setClass(getApplicationContext(), MainActivity.class);
}else {
Log.e("InteractivePostCallBackActivity", "Not starting with user");
}
//Launch the target activity
startActivity(target);
// and die
finish();
}}
47. 47
public class InteractivePostCallBackActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Retrieve the DeepLink
Uri deepLink = Uri.parse(PlusShare.getDeepLinkId(getIntent()));
// Define the Activity that will be launched
Intent target = new Intent();
if (deepLink.isHierarchical() && deepLink.getPath().startsWith("/user/")) {
// Get extra to better target the activity to launch
target.putExtra("profileId", deepLink.getLastPathSegment());//
// Do the same for parameters
if (deepLink.getQueryParameter("action") != null) {
if (deepLink.getQueryParameter("action").contains("see")) {
target.putExtra("action", "see");
}
}
//Then decide which activity you want to launch
target.setClass(getApplicationContext(), MainActivity.class);
}else {
Log.e("InteractivePostCallBackActivity", "Not starting with user");
}
//Launch the target activity
startActivity(target);
// and die
finish();
}}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android2ee.tuto.gplus.signin.publicid"
android:versionCode="1"
android:versionName="1.0" >
<activity
android:name="com.android2ee.tuto.gplus.signin.publicid.InteractivePostCallBackActivity"
android:exported="true" >
<intent-filter>
<action android:name="com.google.android.apps.plus.VIEW_DEEP_LINK" />
<data android:scheme="vnd.google.deeplink" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
50. 50
void writeMomentInStream() {
String userId=mPlusClient.getCurrentPerson().getId();
Person owner = mPlusClient.getCurrentPerson();
ItemScope target = new ItemScope.Builder()
// Also, use ItemScope.setId() to create a unique application specific ID for the item you are writing.
.setId("user/ userId?action=see ")// It should NOT be set as the Google+ user ID. It's your DeepLinkId!
.setText("Your message")
.setDescription(" A description for that")
.setThumbnailUrl(owner.getImage().getUrl())
.setType("http://schema.org/Comment")
.build();
// Ensure in your new PlusClient.Builder(this, this, this).setVisibleActivities("http://schemas.google.com/CommentActivity",
"http://schemas.google.com/ListenActivity").build()
// You have define the activity you want to add as your moment type
Moment moment = new Moment.Builder()
.setType("http://schemas.google.com/CommentActivity")
.setTarget(target)
.build();
if (mPlusClient.isConnected()) {
mPlusClient.writeMoment(moment);
}
Toast.makeText(this, "Moment has been sent", Toast.LENGTH_SHORT).show();
}
Define DeepLinkId
And How Google has to render it
Handle the internet status
and write the moment when connectivity is back
53. 53
Smart, smooth and magic Authentification.
(you can believe in google authentification)
Spread your application.
using the Android install via web to mobile delivery
(interactive posts).
Be part of your user's life and experience
(be in his Google Plus, again interactive posts & application activity).
Be in your user social life
BUT DON'T BE INTRUSIVE
55. 55
L'application My Google Public Profile est disponible sur GitHub :
https://play.google.com/store/apps/details?id=com.android2ee.project.gplus.signin.publicid&hl=fr
56. 56
Retrouvez cette conférence sur SlideShare ou sur Android2ee.com
http://fr.slideshare.net/Android2EE/presentations
http://www.android2ee.com/fr/slideshare/