PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV Mobile 23 → Identifiant unique du terminal en iOS
Identifiant unique du terminal en iOS
Débuté par Jérôme Calame-Rosset, 15 fév. 2016 16:24 - 39 réponses
Membre enregistré
132 messages
Popularité : +1 (1 vote)
Posté le 15 février 2016 - 16:24
Bonjour,

nous souhaitons pouvoir identifier un terminal sous iOS de manière unique. L'idée est de pouvoir attribuer le même numéro de terminal depuis notre webservice même en cas de désinstallation puis réinstallation de l'application.

Or les fonctions iOS SysNumSérie et SysIMEI qui auraient pu nous donner une solution sont indisponibles en iOS.
Nous avons cru comprendre que c'est une limitation Apple pour éviter de "tracer" un appareil puis reconstituer les données en amont (question de protection des données relative à la vie privée).

Mes questions sont les suivantes :
- y a-t-il une autre manière de trouver un identifiant unique de l'appareil (et qu'il soit toujours le même, même en cas de désinstallation / réinstallation de l'application) ?
- si non, est-il possible de crée son propre ID unique (par exemple avec la fonction DonneGUID) et de l'écrire ailleurs que dans le répertoire de l'application histoire de pouvoir le récupérer même après désinstallation puis réinstallation de l'application ?

Merci pour toute aide, avis ou idée!
Membre enregistré
547 messages
Popularité : +1 (1 vote)
Posté le 15 février 2016 - 17:53
Bonjour,

J'ai été confronté au même problème sans avoir trouvé de solution. Pour le moment, j'utilise donc DonneGUID. Mais cela qui en répond pas à votre question.

Par contre, j'ai observé que le token renvoyé pour l'inscription aux notifications Push semblait ne jamais changer. A vérifier !
Je pense que c'est peut-être possible considérant que le token renvoyé par les serveurs android ou apple doivent peut-être le calculer sur la base du imei ?
C'est juste une hypothèse et peut-être une piste...

Si vous investiguez dans ce sens merci de nous renvoyer l'information.

Sinon, écrire un GUID dans le répertoire de l'application ne peut pas être la solution. En effet, le fichier dans lequel vous l'inscririez est effacé à la désinstallation de l'application. A moins, de pouvoir écrire dans un répertoire différent de celui de l'application. Mais est-ce possible?...

Cordialement,
Eric.

--
Eric DELATTRE
http://www.yoosite.fr
Membre enregistré
140 messages
Posté le 16 février 2016 - 07:36
Bonjour, personnellement j'ai créé une procédure en Objective-C, vous créez une procédure normale puis vous la "convertissez".

NSString* AppareilNom()
{
return [[UIDevice currentDevice] name];
}

En espérant que cela va vous aider, peut-être pouvez-vous remplacer "name" par autre chose, je vous laisse voir avec les moteurs de recherche.
Membre enregistré
1 179 messages
Popularité : +9 (11 votes)
Posté le 17 février 2016 - 08:19
Bonjour,

Une appli sous iOS doit permettre un certain nombre d'opérations gratuites à des fins de tests.
La problématique est la même : comment identifier ce matériel de manière unique afin que l'utilisateur ne puisse utiliser indéfiniment l'application en la désinstallant puis en la réinstallant.

Ma question : une seule exécution de DonneGUID() retourne t'elle une valeur unique sur chaque matériel iOS ?
Et ce même si une installation est supprimée puis réinstallée.

Merci pour vos idées...

--
Cordialement
François

http://intra.fr
http://intrasoftware.fr : Guide d'installation de Webdev sur Windows 2012 Server
Webservice d'aide pour gérer l'international
Membre enregistré
41 messages
Posté le 17 février 2016 - 09:03
Bonjour,

En reprenant le code de Gael, et en fouillant la documentation d'Apple, la variable identifierForVendor devrait convenir à vos besoins :
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIDevice_Class/…

A vérifier cependant le comportement exact de cette variable (peu documentée finalement par Apple), notamment en cas de changement de propriétaire de l'iPad (cas fréquent mais qui pourrait poser problème si on se base seulement sur le matériel pour détecter les capacités d'une application : on risque de bloquer les possesseurs qui acquièrent la tablette d'occasion).

Si elle est "reset" à chaque changement de compte propriétaire de l'iPad on est bon. De plus, la documentation suggère que cet Identifier change pour chaque "vendor", ce qui permettrait le respect des informations personnelles de l'utilisateur.

Cordialement,
Membre enregistré
837 messages
Popularité : +5 (9 votes)
Posté le 17 février 2016 - 10:41
Bonjour,

Il faut se baser sur le Device Token il est unique. J'en veux pour preuve que 2 appli différentes utilisée sur le même téléphone renvoient toujours le même Token. Faites le test et vous verrez.
DonneGUID peut changer même sur la même application en exécution.

--
Cordialement,
Camus
Membre enregistré
837 messages
Popularité : +5 (9 votes)
Posté le 17 février 2016 - 10:42
Membre enregistré
1 179 messages
Popularité : +9 (11 votes)
Posté le 17 février 2016 - 11:06
Bonjour Camus,

Merci pour ta contribution.:merci:

Connais tu le code pour obtenir ce Device Token ?

--
Cordialement
François

http://intra.fr
http://intrasoftware.fr : Guide d'installation de Webdev sur Windows 2012 Server
Webservice d'aide pour gérer l'international
Membre enregistré
132 messages
Popularité : +1 (1 vote)
Posté le 17 février 2016 - 11:24
Merci à Eric, Gael, François et Benjamin pour vos réponses et propositions!

@Gael
Ce serait une solution idéale, notre problème est que une chaine de type "iPhone de Jean" a beaucoup trop de chance d'avoir des homonymes.

@Benjamin
C'est ce que l'on utilise jusqu'à présent, avec cette procédure objective-C dont le code est le suivant (je ne le mets pas exprès avec les balises prévus à cet effet car ça casse la casse (sans jeux de mots) et la procédure ne fonctionne plus) :

#import <UIKit/UIKit.h>
NSString* IOS_UDID()
{
NSString* udid;
udid = [UIDevice currentDevice].identifierForVendor.UUIDString;
return udid;
}

Le problème de cette fonction est le suivant :

Il est réinitialisé (donc modifié) lors de chaque réinstallation de l'application ce qui fait que l'on repart de zéro à chaque fois que l'app est désinstallée puis réinstallée (ça crée un nouveau terminal alors que ça devrait reprendre les données stockées jusque là) SAUF si l'on a déjà installé une autre application sur notre iDevice.

Exemple concret avec deux applications de PCsoft (exemples fictifs, ces apps n'existent pas réellement) : com.pcsoft.tames et com.pcsoft.precilia

Situation 1 :tames et precilia sont installées sur le iDevice
- On note le UUID de tames
- On désinstalles l'app tames
- On réinstalles l'app tames
- On vérifie le UUID => c'est le même qu'avant la désinstallation

Situation 2 : uniquement tames est installée et il n'y a aucune autre app com.pcsoft.XXX
- On note le UUID de tames
- On désinstalles l'app tames
- On réinstalles l'app tames
- On vérifie le UUID => l'UUID a changé par rapport à avant la désinstallation

Donc il faudrait obliger l'utilisateur de l'iDevice à avoir une application bidon de sa société avant d'installer l'application réelle/principale. Mais comment le vérifier ? Et est-ce qu'une App de l'App Store fonctionne de manière identique (les déploiements ont été fait ici de manière Ad-hoc et in House on constate la même chose).

@François, @Eric
DonneGUID() retourne un GUID unique mais différent à chaque appel. Du coup on ne peut pas l'invoquer à chaque démarrage de l'application.

La solution serait donc de le générer lors du prmier lancement mais comme Eric l'a très bien mentionné, on ne peut le stocker qu'à à la seule place que permet iOS (soit dans le répertoire "Documents" et ce répertoire est supprimé en même temps que l'application.
Il faut donc chercher à comment écrire ailleurs et là on aurait une solution viable!

Peut-être un début de solution pour écrire ailleurs que dans le Documents ici : http://nshipster.com/uuid-udid-unique-identifier/ en utilisant NSUserDefaults.

Je vais tenter d'essayer d'utiliser cette fonction dans un projet Windev Mobile et je vous tiens au courant.
Membre enregistré
837 messages
Popularité : +5 (9 votes)
Posté le 17 février 2016 - 12:16
François SCHAAL

Regardes la doc sur les notifications Push,
Il faut demander un certificat, après il y a trois ligne a insérer dans le téléphone, elles sont toutes prêtes dans l'exemple fourni et tu envoi le token par webservice.

http://doc.pcsoft.fr/fr-FR/?1000021032

--
Cordialement,
Camus
Membre enregistré
837 messages
Popularité : +5 (9 votes)
Posté le 17 février 2016 - 12:19
Il y a quand même un petit inconvénient c'est qu'il faut que l’utilisateur accepte les notifications à la première ouverture de l'appli. De toute façons il n'y a que cette methode de sur avec Apple parce que jamais tu n'auras un identifiant de téléphone sans l'autorisation explicite de l'utilisateur.

--
Cordialement,
Camus
Membre enregistré
132 messages
Popularité : +1 (1 vote)
Posté le 18 février 2016 - 18:16
Merci Camus pour cette proposition!

Malheureusement après plusieurs tentatives je n'obtiens pas un device token identique. Il est réinitialisé après chaque désinstallation / réinstallation.

Voici comme j'ai procédé :

Code d'initialisation du projet
gbufTokenGUID est un Buffer
NotifPushActive(EnregistreNotifPush)


Procédure EnregistreNotifPush
Procedure EnregistreNotifPush(Token est un Buffer, ErreurNotif est une chaîne)
SI Taille(Token) > 0 ALORS
// Informe le serveur d'application du nouvel identifiant
gbufTokenGUID = Token
ToastAffiche("Token OK")
SINON
// Remonte l'erreur
ToastAffiche("Erreur d'enregistrement : " + ErreurNotif)
FIN


Affichage du token (convertit pour voir quelque chose sur l'IHM) :
LIB_UUDID = "Taille token : "+Taille(gbufTokenGUID)
LIB_GUID = "Token après conversion : "+token_vers_chaine()


Procédure token_vers_chaine
Procedure token_vers_chaine():chaîne
sCh est une chaîne
POUR i=1 _A_ Taille(gbufTokenGUID)
sCh += Asc(gbufTokenGUID[[i]])
FIN
RENVOYER sCh


Qu'avez-vous de différent pour obtenir le même token même après déinstall (de toutes vos apps) puis réinstallation ?

Merci!
Membre enregistré
132 messages
Popularité : +1 (1 vote)
Posté le 18 février 2016 - 18:48
Une autre piste serait d'écrire dans la keychain lors du tout premier lancement de l'application un ID (par la fonction DonneGUID()), puis d'aller systématiquement rechercher cet ID.
Cette solution est réalisable en Objective-C, voici l'aspect théorique (très bien expliqué) : https://blog.onliquid.com/persistent-device-unique-identifier-ios-keychain/

Et l'aspect "pratique" avec le code Objective-C fournit : https://gist.github.com/miguelcma/e8f291e54b025815ca46

La problématique maintenant est de réussir à intégrer ce code dans un projet Windev Mobile. Avez-vous une idée de la façon de s'y prendre pour intégrer ce code dans un projet Windev Mobile ?
Membre enregistré
837 messages
Popularité : +5 (9 votes)
Posté le 19 février 2016 - 00:01
J'avoue que je ne desinstalle pas toutes mes apps mais celle sur laquelle je travaille et le token ne change jamais et de plus il est le meme pour toutes les apps meme si les certificats sont différents. D'ailleurs sil changait pour une il foutrait la pagaille pour l'autre. Mais peut etre que si on desinstalle tout il pourrait changer.... Android ce comporte comme ca aussi. Cest bizarre.

--
Cordialement,
Camus
Membre enregistré
1 179 messages
Popularité : +9 (11 votes)
Posté le 19 février 2016 - 08:25
Bonjour,

Une idée si l'appli est conçue pour un terminal iOS avec les fonctions GSM (donc iPhone) : lors du lancement de l'appli, j'adresse un SMS vers un de mes mobiles avec dans le message un ID (par la fonction DonneGUID()) qui est stocké chez l'utilisateur dans une table locale.

Une autre appli explore les SMS reçus et théoriquement doit pouvoir lire le numéro de téléphone du terminal iOS expéditeur et associer l'ID (en texte) avec le numéro de téléphone.
Si l'appli est désinstallée puis réinstallée, j'expédie un nouveau SMS et même si le Guid diffère, mon numéro de téléphone lui reste le même.

Cela ne fonctionne pas pour les tablettes non GSM.
Réalisable ou non ?

--
Cordialement
François

http://intra.fr
http://intrasoftware.fr : Guide d'installation de Webdev sur Windows 2012 Server
Webservice d'aide pour gérer l'international
Membre enregistré
132 messages
Popularité : +1 (1 vote)
Posté le 19 février 2016 - 10:41
Bonjour Camus, bonjour François,

j'ai testé en conditions réelles les notifications mais j'obtiens à chaque fois un token différent. Peut-être est-ce parce que vous avez généré ce système avant qu'Apple ne change de manière de faire et qu'ils ont conservé pour des raisons historiques ce fonctionnement pour les anciens certificats mais plus pour les nouveaux ?

J'ai désinstallé puis réinstallé l'appli 3 fois, j'ai 4 tokens différents sur mon webservice :





L'idée du SMS me semble lourde à mettre en place car cela sous-entend qu'il faut un terminal de réception des SMS pour chaque client et lorsque la carte SIM est changée (=numéro de téléphone différent) on se retrouve avec la même problématique.

J'explore deux pistes :
- écrire dans la keychain un GUID lors de la toute première installation puis le récupérer lors de chaque réinstallation
- publier sur l'App Store une application "prétexte" qui a le même préfixe que notre application (style com.pcsoft.XXX) ce qui a pour effet de conserver le même identifierForVendor tant qu'au moins une app de notre entreprise reste sur l'iDevice.

Pour rappel voici cette fonction en Objective-C :
#import <UIKit/UIKit.h>
NSString* IOS_UDID()
{
NSString* udid;
udid = [UIDevice currentDevice].identifierForVendor.UUIDString;
return udid;
}

J'ai deux interrogation pour mettre en place cette solution :
- Est-ce que le fonctionnement est identique (non réinitialisation de l'identifierForVendor) avec une app issu de l'App Store et une autre in house?
- Peut-on (au niveau de la licence Apple) fixer un bundle identifier identique pour une application compilée avec un compte développeur différent ?
Membre enregistré
1 179 messages
Popularité : +9 (11 votes)
Posté le 19 février 2016 - 11:26
Bonjour Jérôme,

"L'idée du SMS me semble lourde à mettre en place car cela sous-entend qu'il faut un terminal de réception des SMS pour chaque client et lorsque la carte SIM est changée (=numéro de téléphone différent) on se retrouve avec la même problématique."

Non l'idée était d'envoyer un SMS vers un seul numéro (celui de mon smartphone) avec une appli WM qui va scanner les SMS entrants toutes les .. minutes pour mettre ensuite à jour une base HFSQL avec un couple GUID/numéro de téléphone. Ce numéro de téléphone pourra déjà exister ou non.

Il est à mon avis plus rare de changer de numéro de téléphone que de changer de matériel. Si un client est abonné à un service et change de matériel, l'abonnement peut se poursuivre très simplement puisqu'on aura un nouveau SMS avec un nouveau GUID mais avec le numéro d'un client existant. Si je reçois un SMS avec un numéro de téléphone existant qui n'est pas client mais avec un nouveau GUID, je peux bloquer les fonctionnalités gratuites.
C'est une piste.

Il faudrait aussi chercher s'il est possible de récupérer le compte du smartphone dans l'appstore.
Par ailleurs je prends le cas d'un iPod : dans général, informations, un numéro de série s'affiche et un modèle. Infos récupérables ?

--
Cordialement
François

http://intra.fr
http://intrasoftware.fr : Guide d'installation de Webdev sur Windows 2012 Server
Webservice d'aide pour gérer l'international
Posté le 20 février 2016 - 08:58
sauf erreur de ma part vous ne pouvez pas envoyer un sms sous IOS de manière transparente (en arrière plan) comme sous Android... L'utilisateur Iphone aura connaissance du sms et devra valider l envoi manuellement.
Membre enregistré
1 179 messages
Popularité : +9 (11 votes)
Posté le 21 février 2016 - 09:38
Bonjour Stef,

Bien sûr l'envoi de SMS ne peut se faire qu'avec l'accord de l'utilisateur qu'il suffira d'informer.

j'ai testé mon idée sur Android d'envoi et de récupération d'identifiants : cela fonctionne.
A l'installation de l'appli,un message m'informe de la possibilité de SMS payants.

Autre problème : pour une appli à vocation internationale, l'envoi d'un SMS vers la France est certainement payante. Chez un opérateur français, l'envoi d'un SMS vers l'étranger coûte 0,30€
D'après ce que j'ai pu lire sur le net, Apple ne souhaite pas rendre possible le tracking de ses matériels. Alors oui c'est un vrai problème.

j'ai aussi pensé à l'adresse IP du matériel mais est-elle fixe ou dynamique ?
Je n'ai pas la solution idéale.

--
Cordialement
François

http://intra.fr
http://intrasoftware.fr : Guide d'installation de Webdev sur Windows 2012 Server
Webservice d'aide pour gérer l'international
Membre enregistré
547 messages
Popularité : +1 (1 vote)
Posté le 22 février 2016 - 07:20
Bonjour,

J'ai suivi attentivement ce post très intéressant depuis le début.
Les "verrous" qu'impose Apple semblent incontournables. Il apparaît clairement que les Token, SMS ou encore GUID ne peuvent pas être la solution.

Voici ne autre piste à creuser peut-être...

Le premier point serait de vérifier s'il est possible de "vendre" une application à zéro euro. Apple autorise t'il cela ? dans le cadre d'une période d'essai gratuite peut-être qui pourrait ensuite être étendue à l'infinie...

Si oui, une solution pourrait être d'utiliser les fonctions inApp.

En effet, dans le cas de iOS (probablement la même chose pour android), même en cas de désinstallation de l'application, il est possible de restaurer les précédents achats. (Voir fonction inAppRestaureAchats / http://doc.pcsoft.fr/fr-FR/?1000021034)

Or, il est mentonné dans la page d'aide de la fonction inAppAchèteProduit qu'un reçu de l'achat est renvoyé.

"iPhone/iPad <Reçu> est un buffer contenant le reçu de l’achat. Ce reçu peut ensuite être utilisé pour des vérifications de sécurité supplémentaires auprès du store Apple.". Voir : http://doc.pcsoft.fr/fr-FR/?1000020873&name=inappacheteproduit_fonction

Au regard de la possible restauration des achats, ce "reçu" devrait être logiquement unique, n'est-ce pas ?

Cordialement,
Eric.

--
Eric DELATTRE
http://www.yoosite.fr
Membre enregistré
1 179 messages
Popularité : +9 (11 votes)
Posté le 22 février 2016 - 10:04
Bonjour Eric,

L'idée de l'achat à 0 € est bonne si elle est techniquement possible. Mais qu'en pensera l'utilisateur ?
Pour moi, l'achat d'une appli même à 0 € me semble suspecte si le logiciel annoncé "en version gratuite de démo".
Autre problème : peut-on fixer par appli deux tarifs : un de 0 et un autre de xxx euros? Pas certain.

Je vais réfléchir à une autre solution : de brider ou de limiter certaines fonctionnalités dans les versions d'évaluation ou de limiter l'usage de l'appli à une certaine durée.

C'est encore techniquement le plus simple à réaliser même si un utilisateur désinstalle puis réinstalle l'appli.
Un utilisateur payant pourra être suivi par les fonctions InApp et un SysNumSérie() unique sous Android et un DonneGUID() aléatoire sous iOS (lors de l'achat).

Par contre, si un utilisateur payant change de matériel, comment le retrouver dans la base de données ?

On saura sur le smartphone avec les fonctions InApp qu'il a acheté un service mais ensuite ? Je ne sais pas si l'on peut récupérer avec les fonctions InApp un ID unique d'utilisateur ou un ID unique de transaction qui correspond à l'achat d'une appli... ( ID qui seraient mémorisés).

--
Cordialement
François

http://intra.fr
http://intrasoftware.fr : Guide d'installation de Webdev sur Windows 2012 Server
Webservice d'aide pour gérer l'international
Membre enregistré
132 messages
Popularité : +1 (1 vote)
Posté le 22 février 2016 - 10:19
Bonjour Eric,

j'ai tenté de tester votre solution, malheureusement on est confronté à un problème majeur : cela ne fonctionne que pour les applications de l'App Store car il est apparemment impossible de configurer une application déployée en mode in house pour effectuer un achat inApp (ce qui paraît tout de même justifié).

J'ai aussi essayé tout bêtement d'utiliser la fonction WLangage SauveParamètre, mais comme les accès aux répertoires sont limités uniquement à leurs répertoire ça disparait lors d'une réinstallation.

Pour le moment je n'ai toujours pas de solution, mais je continue de chercher.
Membre enregistré
41 messages
Posté le 22 février 2016 - 11:25
Bonjour,

Je vais prendre l'idée à contre-pieds de tout ce qui a été mentionné jusqu'à présent, en partant du principe que c'est une application en mode in house.

Pourquoi ne pas proposer une application avec un ID en dur à l'intérieur, mais celui ci différent pour chaque device ?

L'idée serait donc de créer autant de fichier IPA qu'il y a de devices, chacun avec exactement le même code source, seul un fichier "uid.txt" serait différent. Ensuite, il faudra s'assurer que chaque device télécharge le bon ipa (avec un contrôle de l'ip, un paramètre dans l'url, n'importe) à chaque mise à jour / installation.

Si le nombre de devices est trop important pour faire ça à la main à chaque fois, on peut imaginer des façons automatiques de faire ça. De tête on a plusieurs solutions ici aussi :
- un script bash sur le mac qui génère lui-même via xCode les XXX.ipa nécessaires avec des uid différents.
- un script PHP qui, au moment du DL de l'ipa, parcourt le fichier IPA (qui n'est qu'un container zip) pour y mettre un ID différent, le referme et le sert à l'iPad. Avantage : n'avoir qu'un seul ipa sur le serveur, donc gain de place. Désavantage : ça oblige à un peu de gymnastique avec du code serveur pour refourguer les bon headers http nécessaires à l'iPad.

L'avantage serait de rendre ça indépendant de toute fonction WL (puisqu'un simple fchargetexte sera nécessaire), et cela peut être fait après compilation par WM.

Cordialement,
Membre enregistré
837 messages
Popularité : +5 (9 votes)
Posté le 22 février 2016 - 12:22
A partir du moment ou Apple refuse la trace des appareils toutes les tentatives seront vaines et même si une solution est trouvée elle sera jugée comme une faille de sécurité et bloquée dans une maj prochaine. La preuve avec les Tokens, tous les forums le disent unique et ce n'est plus le cas.
Par contre l"UUID que vous obtenez précédemment par programmation est une UUID par vendeur et n'a rien à voir avec l'UUID de l'appareil, c'est pourquoi si on désinstalle toutes les apps du vendeur elle change.
Si l'application est une application interne à une entreprise, pourquoi ne pas demander à l’utilisateur à chaque réinstallation de faire un copié collé de l'UUID de l'appareil au premier lancement, Apple ne pourra rien faire contre ça puisque c'est de la saisie utilisateur .

--
Cordialement,
Camus
Posté le 22 février 2016 - 12:22
Bonjour à tous,

voici ma méthode:

quand l'utilisateur démarre l'appli pour la première fois, on lui
demande s'il est nouveau ou a déjà un compte.

Si nouveau, on se connecte à un serveur distant (httprequete+page awp),
et on créé son enreg dans la base. On revoit en réponse l'ID unique
'humaine', de type XXXX-XXXX-XXXX.

On demande à l'utilisateur de noter cette ID.

Si il a réinstallé, on lui demande lID pour l'identifier.

C'est simple, et si l'utilisateur n'a pas noté son ID, c'est sa faute.

Cordialement


--
Fabrice Harari
Consultant WinDev, WebDev et WinDev Mobile International

A votre disposition : WXShowroom.com, WXReplication (open source) et
maintenant WXEDM (open source)

Plus d'information sur http://fabriceharari.com


O
Membre enregistré
130 messages
Popularité : +1 (1 vote)
Posté le 22 février 2016 - 16:05
Bonjour,

Je vous transmets ci-dessous le code permettant d'obtenir un UID permanent.

L'UID obtenu ne changera jamais, même après désinstallation et réinstallation de l'appli.

La méthode se base sur la gestion du Keychain iOS (normalement utilisé pour sauver les mots de passe, mais avantageusement détourné ici pour nos besoins)

Dans votre projet windev, il suffira de faire :
MonUIDUnique est une chaîne= getUID()




Implémentation (A suivre rigoureusement) :
-----------------------------------------------------

1 - Créer la procédure globale objective C suivante dans votre projet windev :


#import "DeviceUID.h"
#import <UIKit/UIKit.h>
NSString* getUID()
{
return [DeviceUID uid];
}





2 - Sauver les fichiers 2 sections suivantes dans les fichiers DeviceUID.h et DeviceUID.m et incluez-les lors de la génération du projet iOS (dans l'écran intitulé "Librairies externes à inclure à la compilation")

//1ere SECTION
//********************************************************************************************************************
//DeviceUID.h
#import <Foundation/Foundation.h>

@interface DeviceUID : NSObject
+ (NSString *)uid;
@end



//2eme SECTION
//*********************************************************************************************************************
//DeviceUID.m
#import "DeviceUID.h"

#import <UIKit/UIKit.h>

@interface DeviceUID ()

@property(nonatomic, strong, readonly) NSString *uidKey;
@property(nonatomic, strong, readonly) NSString *uid;

@end

@implementation DeviceUID

@synthesize uid = _uid;

#pragma mark - Public methods

+ (NSString *)uid {
return [[[DeviceUID alloc] initWithKey:@"deviceUID"] uid];
}

#pragma mark - Instance methods

- (id)initWithKey:(NSString *)key {
self = [super init];
if (self) {
_uidKey = key;
_uid = nil;
}
return self;
}

/*! Returns the Device UID.
The UID is obtained in a chain of fallbacks:
- Keychain
- NSUserDefaults
- Apple IFV (Identifier for Vendor)
- Generate a random UUID if everything else is unavailable
At last, the UID is persisted if needed to.
*/
- (NSString *)uid {
if (!_uid) _uid = [[self class] valueForKeychainKey:_uidKey service:_uidKey];
if (!_uid) _uid = [[self class] valueForUserDefaultsKey:_uidKey];
if (!_uid) _uid = [[self class] appleIFA];
if (!_uid) _uid = [[self class] appleIFV];
if (!_uid) _uid = [[self class] randomUUID];
[self save];
return _uid;
}

/*! Persist UID to NSUserDefaults and Keychain, if not yet saved
*/
- (void)save {
if (![DeviceUID valueForUserDefaultsKey:_uidKey]) {
[DeviceUID setValue:_uid forUserDefaultsKey:_uidKey];
}
if (![DeviceUID valueForKeychainKey:_uidKey service:_uidKey]) {
[DeviceUID setValue:_uid forKeychainKey:_uidKey inService:_uidKey];
}
}

#pragma mark - Keychain methods

/*! Create as generic NSDictionary to be used to query and update Keychain items.
* param1
* param2
*/
+ (NSMutableDictionary *)keychainItemForKey:(NSString *)key service:(NSString *)service {
NSMutableDictionary *keychainItem = [[NSMutableDictionary alloc] init];
keychainItem[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
keychainItem[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAlways;
keychainItem[(__bridge id)kSecAttrAccount] = key;
keychainItem[(__bridge id)kSecAttrService] = service;
return keychainItem;
}

/*! Sets
* param1
* param2
*/
+ (OSStatus)setValue:(NSString *)value forKeychainKey:(NSString *)key inService:(NSString *)service {
NSMutableDictionary *keychainItem = [[self class] keychainItemForKey:key service:service];
keychainItem[(__bridge id)kSecValueData] = [value dataUsingEncoding:NSUTF8StringEncoding];
return SecItemAdd((__bridge CFDictionaryRef)keychainItem, NULL);
}

+ (NSString *)valueForKeychainKey:(NSString *)key service:(NSString *)service {
OSStatus status;
NSMutableDictionary *keychainItem = [[self class] keychainItemForKey:key service:service];
keychainItem[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
keychainItem[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;
CFDictionaryRef result = nil;
status = SecItemCopyMatching((__bridge CFDictionaryRef)keychainItem, (CFTypeRef *)&result);
if (status != noErr) {
return nil;
}
NSDictionary *resultDict = (__bridge_transfer NSDictionary *)result;
NSData *data = resultDict[(__bridge id)kSecValueData];
if (!data) {
return nil;
}
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

#pragma mark - NSUserDefaults methods

+ (BOOL)setValue:(NSString *)value forUserDefaultsKey:(NSString *)key {
[[NSUserDefaults standardUserDefaults] setObject:value forKey:key];
return [[NSUserDefaults standardUserDefaults] synchronize];
}

+ (NSString *)valueForUserDefaultsKey:(NSString *)key {
return [[NSUserDefaults standardUserDefaults] objectForKey:key];
}

#pragma mark - UID Generation methods

+ (NSString *)appleIFA {
NSString *ifa = nil;
Class ASIdentifierManagerClass = NSClassFromString(@"ASIdentifierManager");
if (ASIdentifierManagerClass) { // a dynamic way of checking if AdSupport.framework is available
SEL sharedManagerSelector = NSSelectorFromString(@"sharedManager");
id sharedManager = ((id (*)(id, SEL))[ASIdentifierManagerClass methodForSelector:sharedManagerSelector])(ASIdentifierManagerClass, sharedManagerSelector);
SEL advertisingIdentifierSelector = NSSelectorFromString(@"advertisingIdentifier");
NSUUID *advertisingIdentifier = ((NSUUID* (*)(id, SEL))[sharedManager methodForSelector:advertisingIdentifierSelector])(sharedManager, advertisingIdentifierSelector);
ifa = [advertisingIdentifier UUIDString];
}
return ifa;
}

+ (NSString *)appleIFV {
if(NSClassFromString(@"UIDevice") && [UIDevice instancesRespondToSelector:@selector(identifierForVendor)]) {
// only available in iOS >= 6.0
return [[UIDevice currentDevice].identifierForVendor UUIDString];
}
return nil;
}

+ (NSString *)randomUUID {
if(NSClassFromString(@"NSUUID")) {
return [[NSUUID UUID] UUIDString];
}
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef cfuuid = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
CFRelease(uuidRef);
NSString *uuid = [((__bridge NSString *) cfuuid) copy];
CFRelease(cfuuid);
return uuid;
}

@end



//************************ FIN des sections *****************



Bon dev

Samir BOUCHETIBAT
Membre enregistré
837 messages
Popularité : +5 (9 votes)
Posté le 22 février 2016 - 16:27
Samir,

Cet identifiant est unique par vendeur c'est à dire à toutes les applications d'un même vendeur, d'ailleurs c'est en toutes lettres dans le code. Seulement quand on désinstalle la dernière application de ce vendeur il est régénéré

--
Cordialement,
Camus
Membre enregistré
130 messages
Popularité : +1 (1 vote)
Posté le 22 février 2016 - 16:32
Hello Camus
Je n'utilise PAS le système de vendor ID, et la solution que je donne fonctionne vraiment dans tous les cas (même après désinstallation de l'appli)
Faites le test, vous verrez, c'est magique :)

Bon dev.

Samir BOUCHETIBAT
Membre enregistré
130 messages
Popularité : +1 (1 vote)
Posté le 22 février 2016 - 16:46
Pour être plus clair : le premier appel de l'interface utilise les fonctions standard pour générer un UID quelconque et le sauver dans le Keychain iOS car celui-ci est persistant !
Les prochains appels à la génération UID regardent donc d'abord si un identifiant n'est pas déjà stocké dans le keyChain et le renvoient si trouvé.

Bon dev.
Samir BOUCHETIBAT
Membre enregistré
81 messages
Posté le 22 février 2016 - 17:45
Attention, si le UDID d'un appareil change à chaque suppression de toutes les applications (ou réinitialisation de l'appareil), c'est normal.
Sinon un utilisateur ayant acheté un appareil IOS d'occasion pourrait retrouver toutes les informations de l'ancien utilisateur en réinstallant les mêmes applications que son prédécesseur. S'il s'agit d'une application pour une entreprise, vous pouvez en interdire la suppression, sinon il vaut mieux mettre en place une gestion de compte classique lié à l'adresse mail afin de lier les données de l'utilisateur et qu'ils puissent les retrouver. S'il s'agit d'une application gratuite qui deviens payante au bout de quelques mois, la seule solution serait d'enregistrer la carte bleu de l'utilisateur comme peu le faire un service comme netflix afin d'éviter d'avoir plein d'utilisateurs qui suppriment et réinstallent l'application en boucle tous les mois (au risque de faire chuter le nombre d'utilisateur qui activerait leur mois gratuit...)
Membre enregistré
130 messages
Popularité : +1 (1 vote)
Posté le 22 février 2016 - 17:53
Nico ,
Lors de la cession d'un appareil, une reinitialisation est effectuée.
Le reset remet à vide le keyChain de l'iOS : en utilisant la méthode décrite plus haut, il n'y a donc aucun risque de transférer les droits d'une application à un autre utilisateur.

Bon dev.
Membre enregistré
81 messages
Posté le 22 février 2016 - 17:59
Merci Samir, je n'avais effectivement pas tout lu :p
Cependant s'il est possible de supprimer cet identifiant après une réinitialisation de l'appareil, le soucis deviens le même que pour le changement d'UDID après suppression de toutes les applications (même si j'imagine que des utilisateurs qui vont réinitialiser tous les mois leur appareil pour re-bénéficier d'un mois offert, il ne doit pas y en avoir des masses ;)
Membre enregistré
132 messages
Popularité : +1 (1 vote)
Posté le 23 février 2016 - 08:58
Bonjour Samir,

merci beaucoup pour cette contribution.
Malheureusement je n'arrive pas la mettre en place, j'ai scrupuleusement suivi les instructions mais j'ai des erreurs de compilation sous Xcode. Je suppose que c'est lié à la casse (il y a souvent des problèmes lié au reformatage par le forum) du code Objective-C ou peut-être autre chose ?





Merci pour votre aide!
Membre enregistré
132 messages
Popularité : +1 (1 vote)
Posté le 23 février 2016 - 09:03
Encore une chose, j'ai eu une communication directe de la part d'Apple à ce sujet (donc en dehors de WinDev Mobile), voici leur réponse :

***
Hello Jerome,

I'm responding to your question about identifying a specific iOS device.

Generally, you should use the UIDevice property identifierForVendor.

If you want to create your own identifier so you can control when it's created and how long it stays in existence, use NSUUID. Store this UUID the first time it’s created in either in the app's preferences (NSUserDefaults) or in the keychain. Items in the keychain currently survive if an app is deleted and reinstalled. Both NSUserDefaults and the keychain are preserved across app updates.

We also recommend implementing a user account system where appropriate. Users are accustomed to this approach, and it handles the case where users move to another device or restore their device from a backup. Even with a unique identifier it is still desirable to provide a way for users to migrate to a new device. Login credentials can be stored in the keychain to streamline the login process.

Best regards,
***

L'utilisation de la keychain est donc la solution la plus adaptée à ce problème. Si j'arrive à faire fonctionner la solution de Samir je ferais un petit projet WM pour le mettre à la disposition de tous histoire de résoudre "facilement" cette problématique pour le plus grand nombre.
Membre enregistré
130 messages
Popularité : +1 (1 vote)
Posté le 23 février 2016 - 09:32
Hello Jerome,
Je vais mettre ce matin sur le site de dépôt un petit projet contenant la solution.
Je poste ici le lien dans un petit moment.

Bon dev.
Samir BOUCHETIBAT
Membre enregistré
130 messages
Popularité : +1 (1 vote)
Posté le 23 février 2016 - 10:17
Re-Hello,
Le projet de test est ici :

http://depot.pcsoft.fr/resource.awp…

Jerome : les erreurs de compilation que vous rencontrez viennent de l'absence du framework Security (Il était par défaut dans mon projet)
Dans la génération windev, ajoutez( en plus des fichiers .h et .m) une ligne contenant Security.framework

Bon dev.

Samir BOUCHETIBAT
Membre enregistré
132 messages
Popularité : +1 (1 vote)
Posté le 23 février 2016 - 11:00
Re bonjour Samir,

Effectivement, je confirme: les erreurs de compilation n'apparaissent plus dès lors que l'on rajoute le Security.framework dans les librairies externes à inclure.





Bravo et merci pour cette solution!!! :merci:
Membre enregistré
37 messages
Posté le 01 juillet 2018 - 12:01
Bonjour à tous,
je remonte ce sujet,
est ce qu'avec la nouvelle fonction sysIdentifiant() de WM23 l'id unique ios est fonctionnel ?
ou alors faut l implémenter la solution de Samir ?

merci pour votre retour
Membre enregistré
132 messages
Popularité : +1 (1 vote)
Posté le 02 juillet 2018 - 09:37
Bonjour Amine,

malheureusement ni le SysIdentifiant() ni la solution de Samir ne sont fonctionnels avec la dernière version d'iOS (11.4). Le SysIdentifiant renvoi bien un GUID mais il est unique que pour l'install présente, dès que l'on désinstalle puis réinstall ce GUID change.
Membre enregistré
130 messages
Popularité : +1 (1 vote)
Posté le 10 juillet 2018 - 09:50
Bonjour,
Je confirme qu'APPLE a retiré la persistance des données des Keychains lors de la desinstallation des applications.
En conséquence la méthode d'identification basée sur ce principe ne fonctionne plus.
Il y aurait éventuellement un contournement en déclarant l'application comme partagée, mais aucune solution non officielle ne saurait désormais être pérenne.
Il faut se pencher vers les DeviceCheck APIs.

https://developer.apple.com/documentation/devicecheck

Bon dev