SlideShare une entreprise Scribd logo
1  sur  57
vous présente :
Spécialiste Android
1
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
Wes Tarle Lee Denison
And of course thanks to
https://developers.google.com/events/io/sessions/324806378
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
5
6
Sécurisé
Respectueux des droits que j'accorde
Non intrusif
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)
8
9
10
Rendez-vous : https://code.google.com/apis/console/
Commencez par créer votre projet
Donnez lui un nom
11
Dans OverView, choisissez votre
projectID.
Pas de pression, il doit juste être unique,
un votreNomDePackage.replace(".","-")
devrait suffire.
<-Là
Ce qui donne
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
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
Et voilà, c'est fini pour l'enregistrement de votre projet au sein des services Google.
15
Faire newotherAndroidProject...
et choisir libprojectgoogle_play_service_lib
<-Là
16
Dans le BuildPath du projet, partie Android, ajoutez la librairie google-
play-service (qui est donc dans le workspace).
<-Là
17
18
public class LauncherActivity extends Activity {
private static final String TAG = "MainActivity";
private Intent target = new Intent();
private int activityResult = 11021974;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int gpsuStatusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (gpsuStatusCode != ConnectionResult.SUCCESS) {
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(gpsuStatusCode, this, activityResult);
dialog.show();
} else {
// Else GoogleService are installed => launch your app
target.setClass(getApplicationContext(), MainActivity.class);
startActivity(target);
finish();
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == activityResult && resultCode == RESULT_OK) {
// GoogleService are NOW installed => launch your app
target.setClass(getApplicationContext(), MainActivity.class);
startActivity(target);
}
// what ever happens, die
finish();}
}
public class LauncherActivity extends Activity {
private static final String TAG = "MainActivity";
private Intent target = new Intent();
private int activityResult = 11021974;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int gpsuStatusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (gpsuStatusCode != ConnectionResult.SUCCESS) {
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(gpsuStatusCode, this, activityResult);
dialog.show();
} else {
// Else GoogleService are installed => launch your app
target.setClass(getApplicationContext(), MainActivity.class);
startActivity(target);
finish();
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == activityResult && resultCode == RESULT_OK) {
// GoogleService are NOW installed => launch your app
target.setClass(getApplicationContext(), MainActivity.class);
startActivity(target);
}
// what ever happens, die
finish();}
}
19
public class LauncherActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
int gpsuStatusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (gpsuStatusCode != ConnectionResult.SUCCESS) {
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(gpsuStatusCode, this, activityResult);
dialog.show();
} else {
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
20
21
DirectCall to the
PlusClient Api
22
Activity LifeCycle
onCreate
PlusClient.Builder(this,this,this)
.scope
.visibleActivity
.build()
onStart
onStop
PlusClient.connect()
PlusClient.disconnect()
PlusClient Asynch CallBack
GooglePlayServicesClient.
ConnectionCallbacks
onConnected(Bundle
connectionHint){mPlusClient.getCurrentPerson();
onDisconnected()
PlusClient Asynch CallBack
GooglePlayServicesClient.OnConnection
FailedListener
onConnectionFailed(ConnectionResult result) {
if (result.hasResolution()) {
result.startResolutionForResult(this,
requestCodeResolverError);
Async
onActivityResult
Activity
LifeCycle
onActivityResultAsync
23
/**
* The PlusClient
*/
private PlusClient mPlusClient;
/**
* The connectionResult returned by the last connection try
*/
private ConnectionResult mConnectionResult;
Activity
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();
25
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
@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
@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);
}
}
29
/** * 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
/** * 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"
.....
}
}
32
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
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
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,...
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...)?
37
38
39
PlusClient.getCurrentPerson().getId()
40
private void displayPersonSocialGraph() {
mPlusClient.loadPeople(new OnPeopleLoadedListener() {
@Override
public void onPeopleLoaded(ConnectionResult status, PersonBuffer
personBuffer, String nextPageToken) {
displayLoadedPeople(status, personBuffer, nextPageToken);
}
},
Person.Collection.VISIBLE);
}
public void loadMorePeople() {
mPlusClient.loadPeople(new OnPeopleLoadedListener() {
@Override
public void onPeopleLoaded(ConnectionResult status, PersonBuffer
personBuffer, String nextPageToken) {
displayLoadedPeople(status, personBuffer, nextPageToken);
}
},
Person.Collection.VISIBLE,
Person.OrderBy.ALPHABETICAL,
100,
nextPersonPageToken);
}
private void displayLoadedPeople(ConnectionResult status,
PersonBuffer personBuffer, String nextPageToken) {
this.nextPersonPageToken = nextPageToken;
if (status.isSuccess()) {
try {
for (Person people : personBuffer) {
//Do your stuff
}
} finally {
personBuffer.close();
}
}
41
42
In BrowserOn Android device
43
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
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
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
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>
48
49
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
51
52
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
54
Le projet SignInWithGoogleTutorial est disponible sur GitHub :
https://github.com/MathiasSeguy-Android2EE/SignInWithGoogleTutorial
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
Retrouvez cette conférence sur SlideShare ou sur Android2ee.com
http://fr.slideshare.net/Android2EE/presentations
http://www.android2ee.com/fr/slideshare/
57

Contenu connexe

Tendances

Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose worldFabio Collini
 
STYLISH FLOOR
STYLISH FLOORSTYLISH FLOOR
STYLISH FLOORABU HASAN
 
Handling action bar in Android
Handling action bar in AndroidHandling action bar in Android
Handling action bar in Androidindiangarg
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Mahmoud Hamed Mahmoud
 
ハンズオン資料 電話を作ろう(v1.6用)
ハンズオン資料 電話を作ろう(v1.6用)ハンズオン資料 電話を作ろう(v1.6用)
ハンズオン資料 電話を作ろう(v1.6用)Kenji Sakashita
 
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...Mathias Seguy
 
Android development - Activities, Views & Intents
Android development - Activities, Views & IntentsAndroid development - Activities, Views & Intents
Android development - Activities, Views & IntentsLope Emano
 
What's New in Android
What's New in AndroidWhat's New in Android
What's New in AndroidRobert Cooper
 
Dagger 2 vs koin
Dagger 2 vs koinDagger 2 vs koin
Dagger 2 vs koinJintin Lin
 
ハンズオン資料 電話を作ろう(v2.x用)
ハンズオン資料 電話を作ろう(v2.x用)ハンズオン資料 電話を作ろう(v2.x用)
ハンズオン資料 電話を作ろう(v2.x用)Kenji Sakashita
 
Android basic 4 Navigation Drawer
Android basic 4 Navigation DrawerAndroid basic 4 Navigation Drawer
Android basic 4 Navigation DrawerEakapong Kattiya
 
Vaadin 7 CN
Vaadin 7 CNVaadin 7 CN
Vaadin 7 CNjojule
 
안드로이드 데이터 바인딩
안드로이드 데이터 바인딩안드로이드 데이터 바인딩
안드로이드 데이터 바인딩GDG Korea
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolboxShem Magnezi
 
Why SOLID matters - even for JavaScript
Why SOLID matters - even for JavaScriptWhy SOLID matters - even for JavaScript
Why SOLID matters - even for JavaScriptmartinlippert
 
Vaadin DevDay 2017 - DI your UI
Vaadin DevDay 2017 - DI your UIVaadin DevDay 2017 - DI your UI
Vaadin DevDay 2017 - DI your UIPeter Lehto
 
Local Notification Tutorial
Local Notification TutorialLocal Notification Tutorial
Local Notification TutorialKetan Raval
 

Tendances (20)

Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose world
 
STYLISH FLOOR
STYLISH FLOORSTYLISH FLOOR
STYLISH FLOOR
 
Handling action bar in Android
Handling action bar in AndroidHandling action bar in Android
Handling action bar in Android
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
 
ハンズオン資料 電話を作ろう(v1.6用)
ハンズオン資料 電話を作ろう(v1.6用)ハンズオン資料 電話を作ろう(v1.6用)
ハンズオン資料 電話を作ろう(v1.6用)
 
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...
 
Android development - Activities, Views & Intents
Android development - Activities, Views & IntentsAndroid development - Activities, Views & Intents
Android development - Activities, Views & Intents
 
What's New in Android
What's New in AndroidWhat's New in Android
What's New in Android
 
Dagger 2 vs koin
Dagger 2 vs koinDagger 2 vs koin
Dagger 2 vs koin
 
ハンズオン資料 電話を作ろう(v2.x用)
ハンズオン資料 電話を作ろう(v2.x用)ハンズオン資料 電話を作ろう(v2.x用)
ハンズオン資料 電話を作ろう(v2.x用)
 
Android basic 4 Navigation Drawer
Android basic 4 Navigation DrawerAndroid basic 4 Navigation Drawer
Android basic 4 Navigation Drawer
 
Vaadin 7 CN
Vaadin 7 CNVaadin 7 CN
Vaadin 7 CN
 
안드로이드 데이터 바인딩
안드로이드 데이터 바인딩안드로이드 데이터 바인딩
안드로이드 데이터 바인딩
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolbox
 
Why SOLID matters - even for JavaScript
Why SOLID matters - even for JavaScriptWhy SOLID matters - even for JavaScript
Why SOLID matters - even for JavaScript
 
Lab1-android
Lab1-androidLab1-android
Lab1-android
 
Android
AndroidAndroid
Android
 
Vaadin DevDay 2017 - DI your UI
Vaadin DevDay 2017 - DI your UIVaadin DevDay 2017 - DI your UI
Vaadin DevDay 2017 - DI your UI
 
Local Notification Tutorial
Local Notification TutorialLocal Notification Tutorial
Local Notification Tutorial
 
Introduction to android
Introduction to androidIntroduction to android
Introduction to android
 

En vedette

Mise en place de l'ActionBarCompat dans vos projets Android.
Mise en place de l'ActionBarCompat dans vos projets Android.Mise en place de l'ActionBarCompat dans vos projets Android.
Mise en place de l'ActionBarCompat dans vos projets Android.Mathias Seguy
 
Treatment, Architecture and Threads
Treatment, Architecture and ThreadsTreatment, Architecture and Threads
Treatment, Architecture and ThreadsMathias Seguy
 
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2Mathias Seguy
 
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...Mathias Seguy
 
Android un nouveau futur s'ouvre à nous
Android un nouveau futur s'ouvre à nousAndroid un nouveau futur s'ouvre à nous
Android un nouveau futur s'ouvre à nousMathias Seguy
 
CocoaHeads An Android Overview (fr)
CocoaHeads An Android Overview (fr)CocoaHeads An Android Overview (fr)
CocoaHeads An Android Overview (fr)Mathias Seguy
 
Voyage en monde Android. Trucs et astuces tout au long de la route.
Voyage en monde Android. Trucs et astuces tout au long de la route.Voyage en monde Android. Trucs et astuces tout au long de la route.
Voyage en monde Android. Trucs et astuces tout au long de la route.Mathias Seguy
 
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)Mathias Seguy
 
Android2EE training: Tutorials list of Android projects
Android2EE training: Tutorials list of Android projectsAndroid2EE training: Tutorials list of Android projects
Android2EE training: Tutorials list of Android projectsMathias Seguy
 
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015Mathias Seguy
 
The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]Nilhcem
 
Animate me, If you don't do it for me do it for Chet :)
Animate me, If you don't do it for me do it for Chet :)Animate me, If you don't do it for me do it for Chet :)
Animate me, If you don't do it for me do it for Chet :)Mathias Seguy
 
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiquePrésentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiqueDenis Voituron
 
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1Mathias Seguy
 

En vedette (14)

Mise en place de l'ActionBarCompat dans vos projets Android.
Mise en place de l'ActionBarCompat dans vos projets Android.Mise en place de l'ActionBarCompat dans vos projets Android.
Mise en place de l'ActionBarCompat dans vos projets Android.
 
Treatment, Architecture and Threads
Treatment, Architecture and ThreadsTreatment, Architecture and Threads
Treatment, Architecture and Threads
 
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2
 
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...
 
Android un nouveau futur s'ouvre à nous
Android un nouveau futur s'ouvre à nousAndroid un nouveau futur s'ouvre à nous
Android un nouveau futur s'ouvre à nous
 
CocoaHeads An Android Overview (fr)
CocoaHeads An Android Overview (fr)CocoaHeads An Android Overview (fr)
CocoaHeads An Android Overview (fr)
 
Voyage en monde Android. Trucs et astuces tout au long de la route.
Voyage en monde Android. Trucs et astuces tout au long de la route.Voyage en monde Android. Trucs et astuces tout au long de la route.
Voyage en monde Android. Trucs et astuces tout au long de la route.
 
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
 
Android2EE training: Tutorials list of Android projects
Android2EE training: Tutorials list of Android projectsAndroid2EE training: Tutorials list of Android projects
Android2EE training: Tutorials list of Android projects
 
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
 
The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]
 
Animate me, If you don't do it for me do it for Chet :)
Animate me, If you don't do it for me do it for Chet :)Animate me, If you don't do it for me do it for Chet :)
Animate me, If you don't do it for me do it for Chet :)
 
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiquePrésentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
 
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
 

Similaire à Android Specialist Training

[Android] Google Service Play & Google Maps
[Android] Google Service Play & Google Maps[Android] Google Service Play & Google Maps
[Android] Google Service Play & Google MapsNatã Melo
 
Google Integration in Android Apps - Mooscon 2013 Cebit
Google Integration in Android Apps - Mooscon 2013 CebitGoogle Integration in Android Apps - Mooscon 2013 Cebit
Google Integration in Android Apps - Mooscon 2013 CebitFriedger Müffke
 
Let's your users share your App with Friends: App Invites for Android
 Let's your users share your App with Friends: App Invites for Android Let's your users share your App with Friends: App Invites for Android
Let's your users share your App with Friends: App Invites for AndroidWilfried Mbouenda Mbogne
 
Integrating GoogleFit into Android Apps
Integrating GoogleFit into Android AppsIntegrating GoogleFit into Android Apps
Integrating GoogleFit into Android AppsGiles Payne
 
Exploring Google (Cloud) APIs with Python & JavaScript
Exploring Google (Cloud) APIs with Python & JavaScriptExploring Google (Cloud) APIs with Python & JavaScript
Exploring Google (Cloud) APIs with Python & JavaScriptwesley chun
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andevMike Nakhimovich
 
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Alina Vilk
 
Google Cloud Messaging
Google Cloud MessagingGoogle Cloud Messaging
Google Cloud MessagingAshiq Uz Zoha
 
Cómo tener analíticas en tu app y no volverte loco
Cómo tener analíticas en tu app y no volverte locoCómo tener analíticas en tu app y no volverte loco
Cómo tener analíticas en tu app y no volverte locoGemma Del Olmo
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidDaniel Baccin
 
Writing JavaScript that doesn't suck
Writing JavaScript that doesn't suckWriting JavaScript that doesn't suck
Writing JavaScript that doesn't suckRoss Bruniges
 
Mooscon 2013 cebit - google integration in android apps (1)
Mooscon 2013   cebit - google integration in android apps (1)Mooscon 2013   cebit - google integration in android apps (1)
Mooscon 2013 cebit - google integration in android apps (1)Heinrich Seeger
 
Guice tutorial
Guice tutorialGuice tutorial
Guice tutorialAnh Quân
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to javaciklum_ods
 
The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]Nilhcem
 

Similaire à Android Specialist Training (20)

[Android] Google Service Play & Google Maps
[Android] Google Service Play & Google Maps[Android] Google Service Play & Google Maps
[Android] Google Service Play & Google Maps
 
Google Integration in Android Apps - Mooscon 2013 Cebit
Google Integration in Android Apps - Mooscon 2013 CebitGoogle Integration in Android Apps - Mooscon 2013 Cebit
Google Integration in Android Apps - Mooscon 2013 Cebit
 
Let's your users share your App with Friends: App Invites for Android
 Let's your users share your App with Friends: App Invites for Android Let's your users share your App with Friends: App Invites for Android
Let's your users share your App with Friends: App Invites for Android
 
Integrating GoogleFit into Android Apps
Integrating GoogleFit into Android AppsIntegrating GoogleFit into Android Apps
Integrating GoogleFit into Android Apps
 
Exploring Google (Cloud) APIs with Python & JavaScript
Exploring Google (Cloud) APIs with Python & JavaScriptExploring Google (Cloud) APIs with Python & JavaScript
Exploring Google (Cloud) APIs with Python & JavaScript
 
Activity
ActivityActivity
Activity
 
Activity
ActivityActivity
Activity
 
Activity
ActivityActivity
Activity
 
Activity
ActivityActivity
Activity
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andev
 
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
 
Google Cloud Messaging
Google Cloud MessagingGoogle Cloud Messaging
Google Cloud Messaging
 
Cómo tener analíticas en tu app y no volverte loco
Cómo tener analíticas en tu app y no volverte locoCómo tener analíticas en tu app y no volverte loco
Cómo tener analíticas en tu app y no volverte loco
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender android
 
Writing JavaScript that doesn't suck
Writing JavaScript that doesn't suckWriting JavaScript that doesn't suck
Writing JavaScript that doesn't suck
 
Mooscon 2013 cebit - google integration in android apps (1)
Mooscon 2013   cebit - google integration in android apps (1)Mooscon 2013   cebit - google integration in android apps (1)
Mooscon 2013 cebit - google integration in android apps (1)
 
Google GIN
Google GINGoogle GIN
Google GIN
 
Guice tutorial
Guice tutorialGuice tutorial
Guice tutorial
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]
 

Android Specialist Training

  • 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
  • 5. 5
  • 6. 6 Sécurisé Respectueux des droits que j'accorde Non intrusif
  • 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)
  • 8. 8
  • 9. 9
  • 10. 10 Rendez-vous : https://code.google.com/apis/console/ Commencez par créer votre projet Donnez lui un nom
  • 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.
  • 15. 15 Faire newotherAndroidProject... et choisir libprojectgoogle_play_service_lib <-Là
  • 16. 16 Dans le BuildPath du projet, partie Android, ajoutez la librairie google- play-service (qui est donc dans le workspace). <-Là
  • 17. 17
  • 18. 18 public class LauncherActivity extends Activity { private static final String TAG = "MainActivity"; private Intent target = new Intent(); private int activityResult = 11021974; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); int gpsuStatusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); if (gpsuStatusCode != ConnectionResult.SUCCESS) { Dialog dialog = GooglePlayServicesUtil.getErrorDialog(gpsuStatusCode, this, activityResult); dialog.show(); } else { // Else GoogleService are installed => launch your app target.setClass(getApplicationContext(), MainActivity.class); startActivity(target); finish(); } } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == activityResult && resultCode == RESULT_OK) { // GoogleService are NOW installed => launch your app target.setClass(getApplicationContext(), MainActivity.class); startActivity(target); } // what ever happens, die finish();} }
  • 19. public class LauncherActivity extends Activity { private static final String TAG = "MainActivity"; private Intent target = new Intent(); private int activityResult = 11021974; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); int gpsuStatusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); if (gpsuStatusCode != ConnectionResult.SUCCESS) { Dialog dialog = GooglePlayServicesUtil.getErrorDialog(gpsuStatusCode, this, activityResult); dialog.show(); } else { // Else GoogleService are installed => launch your app target.setClass(getApplicationContext(), MainActivity.class); startActivity(target); finish(); } } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == activityResult && resultCode == RESULT_OK) { // GoogleService are NOW installed => launch your app target.setClass(getApplicationContext(), MainActivity.class); startActivity(target); } // what ever happens, die finish();} } 19 public class LauncherActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { int gpsuStatusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); if (gpsuStatusCode != ConnectionResult.SUCCESS) { Dialog dialog = GooglePlayServicesUtil.getErrorDialog(gpsuStatusCode, this, activityResult); dialog.show(); } else { } } protected void onActivityResult(int requestCode, int resultCode, Intent data) { }
  • 20. 20
  • 21. 21
  • 22. DirectCall to the PlusClient Api 22 Activity LifeCycle onCreate PlusClient.Builder(this,this,this) .scope .visibleActivity .build() onStart onStop PlusClient.connect() PlusClient.disconnect() PlusClient Asynch CallBack GooglePlayServicesClient. ConnectionCallbacks onConnected(Bundle connectionHint){mPlusClient.getCurrentPerson(); onDisconnected() PlusClient Asynch CallBack GooglePlayServicesClient.OnConnection FailedListener onConnectionFailed(ConnectionResult result) { if (result.hasResolution()) { result.startResolutionForResult(this, requestCodeResolverError); Async onActivityResult Activity LifeCycle onActivityResultAsync
  • 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();
  • 25. 25
  • 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); } }
  • 29. 29
  • 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" ..... } }
  • 32. 32
  • 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...)?
  • 37. 37
  • 38. 38
  • 40. 40 private void displayPersonSocialGraph() { mPlusClient.loadPeople(new OnPeopleLoadedListener() { @Override public void onPeopleLoaded(ConnectionResult status, PersonBuffer personBuffer, String nextPageToken) { displayLoadedPeople(status, personBuffer, nextPageToken); } }, Person.Collection.VISIBLE); } public void loadMorePeople() { mPlusClient.loadPeople(new OnPeopleLoadedListener() { @Override public void onPeopleLoaded(ConnectionResult status, PersonBuffer personBuffer, String nextPageToken) { displayLoadedPeople(status, personBuffer, nextPageToken); } }, Person.Collection.VISIBLE, Person.OrderBy.ALPHABETICAL, 100, nextPersonPageToken); } private void displayLoadedPeople(ConnectionResult status, PersonBuffer personBuffer, String nextPageToken) { this.nextPersonPageToken = nextPageToken; if (status.isSuccess()) { try { for (Person people : personBuffer) { //Do your stuff } } finally { personBuffer.close(); } }
  • 41. 41
  • 42. 42
  • 43. In BrowserOn Android device 43
  • 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>
  • 48. 48
  • 49. 49
  • 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
  • 51. 51
  • 52. 52
  • 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
  • 54. 54 Le projet SignInWithGoogleTutorial est disponible sur GitHub : https://github.com/MathiasSeguy-Android2EE/SignInWithGoogleTutorial
  • 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/
  • 57. 57