Expo get unique device id without ejecting - android

This library allows you to get unique device id / Mac address of Android devices, which doesn't change after reinstallation.
Expo.Constants.deviceId changes after every reinstallation (even if the app version number is the same).
Is there a way to get an unique id for Android that doesn't change after reinstallation (at least for if it's the same version), without ejecting?

For Expo IOS theres currently very limited options, Since Apple forbids getting private device info. We will need to create our own unique identifier below.
Solution:
My solution is a combination of uuid and Expo SecureStore works for IOS and Android.
import * as SecureStore from 'expo-secure-store';
import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';
let uuid = uuidv4();
await SecureStore.setItemAsync('secure_deviceid', JSON.stringify(uuid));
let fetchUUID = await SecureStore.getItemAsync('secure_deviceid');
console.log(fetchUUID)
This solution will work even if app gets reinstalled, or if user switches devices and copy's all data to new device.
(Expo.Constants.deviceId is deprecated and will be removed in Expo SDK 44).
Full Example:
To check if you already stored the uuid in SecureStore
import * as SecureStore from 'expo-secure-store';
import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';
let uuid = uuidv4();
let fetchUUID = await SecureStore.getItemAsync('secure_deviceid');
//if user has already signed up prior
if (fetchUUID) {
uuid = fetchUUID
}
await SecureStore.setItemAsync('secure_deviceid', JSON.stringify(uuid));
console.log(uuid)

Use Application.androidId from expo-application. Id will not change after reinstall or update. The value may change if a factory reset is performed on the device or if an APK signing key changes.
https://docs.expo.dev/versions/latest/sdk/application/#applicationandroidid
Example:
import * as Application from 'expo-application';
import { Platform } from 'expo-modules-core';
import * as SecureStore from 'expo-secure-store';
import Constants from 'expo-constants';
const getDeviceId = async () => {
if (Platform.OS === 'android') {
return Application.androidId;
} else {
let deviceId = await SecureStore.getItemAsync('deviceId');
if (!deviceId) {
deviceId = Constants.deviceId; //or generate uuid
await SecureStore.setItemAsync('deviceId', deviceId);
}
return deviceId;
}
}

Guess you can use facebook module for this purpose.
https://docs.expo.io/versions/latest/sdk/facebook-ads/#currentdevicehash
Not sure what happens under hood - but looks like it unique between app reinstal, device restart etc.

Just use getuniqueid() method from react-native-device-info. Works on iOS and android to uniquely identify a device .

To get the device UniqueId in expo project,
npm install react-native-device-info
expo run:ios or expo run:android
Please note: expo start will throw an error

Related

Flutter device_info_plus 'androidId' is not unique. How can I identify an android users device even after reinstalls or updates?

I am using the device_info_plus plugin like this:
Future<void> getHardwareID() async {
final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
if (Platform.isAndroid) {
final AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
hwid = androidInfo.androidId;
} else if (Platform.isIOS) {
final IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
hwid = iosInfo.identifierForVendor;
}
}
The issue is that when I use the same phone with different versions of the app - so if I upload a new bundle for testing for instance - then androidInfo.androidId will be something different. I suppose this is what they mean with the description
The Android hardware device ID that is unique between the device +
user and app signing.
Eventhough I think with app signing they mean the keystore file and properties which do not change so I am not sure if this is the reason
Apple seems to work fine since iosInfo.identifierForVendor just returns the
Unique UUID value identifying the current device
This is a problem since I would like to keep track of users in a database without them having to register with an account. (How) Is this possible?
There is an id property described like this:
Either a changelist number, or a label like M4-rc20
But that does not sound like what I am looking for
How can I get an ID from an android device that does not change if the app version changes?

google_sign_in Flutter plugin always returns null serverAccessCode

I have the current workflow for my authentication
User signs in via google OAuth2
User is then given a server_auth_code which they send to my backend authentication
The auth code is validated on the back end and users is sent a JWT
I had this all working in raw Java with the Android SDK, but Flutter seemed a lot nicer. But now when using the google_sign_in plugin on android, I am unable to retrieve the serverAuthCore anymore, this plugin just wants to return null the entire time.
I Am using the client ID that's specified for Android, however, I tested the WebApplication that's auto-generated by google too but that's the same issue (Null serverAutHCode)
This is the code that I am currently using:
/// Provides the `GoogleSignIn` class
import 'package:google_sign_in/google_sign_in.dart';
class GoogleLoginPage extends StatefulWidget {
final String name = "Logging in with google.";
late GoogleSignIn _googleSignIn;
GoogleLoginPage() : super() {
_googleSignIn = GoogleSignIn(
scopes: ['https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile'],
serverClientId: "XX-XXX.apps.googleusercontent.com"
);
}
Future<void> fetchAuthToken() async {
try {
var response = await _googleSignIn.signIn();
log(response?.serverAuthCode ?? "No server auth code");
_googleSignIn.signOut();
} catch (error) {
print("ERR");
print(error);
}
}
#override
State<GoogleLoginPage> createState() => GoogleLoginState();
}
The output of this code is: [log] No server auth code
The question:
Am I doing something wrong? As mentioned this works 100% on my java project using the google play services SDK so I know it's nothing to do with my google console configurations.
Okay so I figured out the issues:
It appears that by default the google login plugin for flutter comes on an older version (If I remember correctly it was 20.0.5)
I Simply changed the version to the latest version:
'com.google.android.gms:play-services-auth:20.2.0'
You can do this by editing the project's build.gradle (In IntelliJ you open build.gradle and click "Open for editing in the android studio" in the top right, from there you need to find the gradle file for google_sign_in, and change the import there, remember to click sync in the top right of android studio before you close out of it)
And I began to receive my serverAuthCode as normal, cheers!

How to access iOS UserDefaults stored data in Flutter SharedPrefrences

I have an iOS app already on Store, Now planning to replace it with Flutter with new version release.
I want to get access native app's UserDefaults data in Flutter code.
Using the way suggested in Flutter docs I m getting null value. What I have tried is:
In my pubspec.yaml file :
dependencies:
shared_preferences: ^0.5.12+4
Im my home.dart class file I'm importing header :
import 'package:shared_preferences/shared_preferences.dart';
And this is how I m trying to access data stored in iOS app from native app, I m using same bundle ID (Package ID) in flutter project to overwrite the app and it is successfully overwriting.
#override
void initState() {
super.initState();
getFromLocalMemory('user').then((value) =>
userInfo = value
);
}
Future<String> getFromLocalMemory(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String user = prefs.getString(key);
return user;
}
It always returns null. While 'user' key has data when getting from iOS native app.
We can use existing plugin native_shared_preferences. It allows us to access native SharedPreferences on Android and UserDefaults on iOS.
Sample code to read a value by key "SomeKey":
final someKey = "SomeKey";
var prefs = await NativeSharedPreferences.getInstance();
if (prefs.containsKey(someKey)) {
print("Value for SomeKey: ${prefs.get(someKey)}");
}
In that case, I suggest you use platform channel method
platform channels
iOS doesn't seem to allow flutter framework to access NSUserDefaults, when it didn't create it from the beginning,..
I hope it will work for you.

How to Get Location data from Photos in React Native Android 10

MediaStore.Images.Media.LATITUDE and MediaStore.Images.Media.LONGITUDE was deprecated in Android Q.
Does anyway know how we can get the Media location on React Native with expo? Basically do the below without Ejecting.
Android 10: fetch the gallery via MediaStore with location information
Thank you
import * as Permissions from 'expo-permissions';
import * as MediaLibrary from 'expo-media-library';
import Exif from 'react-native-exif'
...
MediaLibrary.getAssetInfoAsync(asset).then(function (e) {
console.log("Location is ", e.location); //always null
if (e.location) {
data.push(e);
}
});
Exif.getLatLong(asset) //doesn't get location.
.then((loc) => { console.log('Location OK: ', loc) })
.catch(msg => console.log('messages: ' + msg))
This may be an issue if you're using a real device and not an emulator.
When I use the iOS simulator, there are no issues getting the location with this method, if the image contains any location data.
const imageData = await MediaLibrary.getAssetInfoAsync(assetId);
console.log(imageData.location)
How ever, on my physical android device the locations field also resolves to null.
Even though the image i'm testing with is the same.
But when I use expo ImagePicker, location is shown if the image contains the informations.
Also, it may be unnecessary to use react-native-exif; the method getAssetInfoAsync already returns the image EXIF data.

Flutter - Get Unique Device ID

I am making an app with token based system. So users can buy tokens and using them they can make some actions.
Each user gets 10 tokens for free (as a trial version) after creating an account using email and password.
I want to prevent that user gets another 10 tokens by getting a new account each time and I was wondering if there is something like unique device ID for both Android and iOS devices?
Can I use this for that purpose? https://pub.dartlang.org/packages/device_id#-example-tab-
Use device_info_plus plugin.
In your pubspec.yaml file add this
dependencies:
device_info_plus: any
Create a method:
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
// ...
Future<String?> _getId() async {
var deviceInfo = DeviceInfoPlugin();
if (Platform.isIOS) { // import 'dart:io'
var iosDeviceInfo = await deviceInfo.iosInfo;
return iosDeviceInfo.identifierForVendor; // Unique ID on iOS
} else {
var androidDeviceInfo = await deviceInfo.androidInfo;
return androidDeviceInfo.androidId; // Unique ID on Android
}
}
Use it like:
String? deviceId = await _getId();
or
_getId().then((id) {
String? deviceId = id;
});
Yes thats the plugin you need. If you really want to
I want to prevent that user gets another 10 tokens by getting a new account each time
You must as well check for rooted phone (it can change id)
You may want to consider using this GET IMEI

Categories

Resources