iOS Firebase CrashlyticsKit not setting user ID - ios

I am trying to set a user ID for Firebase Crashlytics reports.
Currently I send a user ID only if it's not sent or is changed (very rare event). And there is no user ID in crash reports.
My code:
+ (void)setCrashlyticsUserData:(User *)user
{
if (user == nil) { return; }
NSString *userIdKey = #"CRASHLYTICS_SENT_USER_ID";
NSUserDefaults *userDefaults = NSUserDefaults.standardUserDefaults;
NSInteger sentUserId = [userDefaults integerForKey:userIdKey];
if (sentUserId == user.userId) { return; }
[CrashlyticsKit setUserIdentifier:[NSString stringWithFormat:#"%i", user.userId]];
[userDefaults setInteger:user.userId forKey:userIdKey];
}
If this line is commented if (sentUserId == user.userId) { return; } I receive a user ID in crash reports.
Should I call [CrashlyticsKit setUserIdentifier:] every app launch? I can't find any information about it in the documentation.

Custom attributes of Crashlytics (like custom keys or user identifier) works in log-style in per-session basis.
So, you should call setUserIdentifier in each app session as early as possible.
See this link for code example:
https://fabric.io/kits/ios/crashlytics/features

You can use [Crashlytics setUserIdentifier:] to provide an id number, token, or hashed value that uniquely identifies the end-user of your application without disclosing or transmitting any of their personal information. You can also clear the value by setting it to a blank string. This value is displayed right in the Crashlytics dashboard.
[CrashlyticsKit setUserIdentifier:#"123456789"]; //User ID
Or another option is setthe custom key using [CrashlyticsKit setObjectValue:forKey:], See the following example.
[CrashlyticsKit setIntValue:3 forKey:#"userid"];
[CrashlyticsKit setObjectValue:#"logged_in" forKey:#"last_UI_action"];
See this document for more information.
https://docs.fabric.io/apple/crashlytics/enhanced-reports.html

Related

User list for pubnub-chat objective c

I have application where pubnub chat feature is been used.
I want to perform below feature
1)register / login user in pubnub programatically for chat
2)Get list of the all the users
3)Make friend and send 1st message to the user
I am aware about how to create the channel. I had created channel by below code :
PNConfiguration *configuration = [PNConfiguration configurationWithPublishKey:#"pub-c-XXXXXXXXXXXX-a2bf-XXXX-XXXX-XXXXXXXXXXXX"subscribeKey:#"sub-c-XXXXXXXXXXXX-02d0-XXXX-XXXX-XXXXXXXXXXXX"];
self.client = [PubNub clientWithConfiguration:configuration];
//[self.client addListener:self];
[self.client subscribeToChannels: #[#"my_channel"] withPresence:YES];
I get the channel architecture by : http://pubnub.github.io/pubnub-design-patterns/2015/03/05/Inbound-Channel-Pattern.html
But how do i get the list of the users and their channel and send the message.
I also found this : https://www.pubnub.com/docs/ios-objective-c/presence-sdk-v4
but this only show the friends status. whether they are online / offline by
Join
leave
timeout
Please advice and help
Code to find the list of the users are below but still is show the ZERO users:
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
PNConfiguration *configuration = [PNConfiguration configurationWithPublishKey:#"pub-c-XXXXXXXXXXXX-a2bf-XXXX-XXXX-XXXXXXXXXXXX"subscribeKey:#"sub-c-XXXXXXXXXXXX-02d0-XXXX-XXXX-XXXXXXXXXXXX"];
self.client = [PubNub clientWithConfiguration:configuration];
//Subscription process results arrive to listener which should adopt to PNObjectEventListener protocol and registered using:
[self.client addListener:self];
//Listeners callbacks:
[self.client subscribeToChannels: #[#"XXX"] withPresence:YES];
configuration.uuid = #"XXX";
[self.client hereNowForChannel:#"XXX" withVerbosity:PNHereNowState
completion:^(PNPresenceChannelHereNowResult *result,
PNErrorStatus *status) {
// Check whether request successfully completed or not.
if (!status.isError) {
NSLog(#"list of users %#", result.data.uuids);
NSLog(#"list of result.data.occupancy %#", result.data.occupancy);
// result.data.uuids - dictionary with active subscriber. Each entry will have next
// fields: "uuid" - identifier and "state" if it has been provided.
// result.data.occupancy - total number of active subscribers.
}
// Request processing failed.
else {
NSLog(#"FAIL");
// Handle presence audit error. Check 'category' property to find
// out possible issue because of which request did fail.
//
// Request can be resent using: [status retry];
}
}];
}
PubNub Here Now with State
You need to call hereNowForChannel with withVerbosity:PNHereNowState to get the user's state along with all the subscribed users.
The Objective-C SDK API Reference Docs for hereNowForChannel has more details.
Looking at the code, if you always set the UUID to #"XXX" you will only ever have 1 user. The Presence add-on for PubNub uses the UUID property to track active users on a channel, and if you only use 1 UUID PubNub will treat every client as the same client.
Here is our knowledge base article on setting the UUID
https://www.pubnub.com/knowledge-base/discussion/138/how-do-i-set-the-uuid
Also, the iOS PubNub SDK will create and reuse the UUID automatically. This is a new feature as of the 4.2 sdk.
https://www.pubnub.com/docs/ios-objective-c/api-reference-sdk-v4#uuid_example_2

Check if user is connected to his Apple Account, if not, ask him to connect to it

Is it possible to check if the user is connected to his Apple Account ? And if he is not, ask him to connect ?
Yes it is possible to get Apple account (iCloud) status by checking if the ubiquityIdentityToken object in NSFileManager is set. You can use something like this:
Swift 4
var iCloudAvailability: Bool {
return FileManager.default.ubiquityIdentityToken != nil
}
Swift 3
var icloudStatus: Bool {
return NSFileManager.defaultManager().ubiquityIdentityToken != nil ? true : false
}
Value of true would indicate that user is logged in, and false that user is not logged in, so you can present some kind of view to ask user to connect.
From the Apple documentation:
When iCloud is currently available, this property contains an opaque object representing the identity of the current user. If iCloud is unavailable for any reason or there is no logged-in user, the value of this property is nil. Accessing the value of this property is relatively fast so you can check the value at launch time from your app’s main thread.
If you are checking for iCloud services then from CloudKit you can use CKContainer class to get user account status as below
CKContainer *container = [CKContainer defaultContainer];
[container accountStatusWithCompletionHandler:^(CKAccountStatus accountStatus, NSError * _Nullable error) {
//Here goes your code to handle the account status
}];
iOS 10.x swift 4.0 Based on the Said Sikira answer
func icloudStatus() -> Bool?{
return FileManager.default.ubiquityIdentityToken != nil ? true : false
}

Why does iOS get a new identifierForVendor when app updates?

Every time my app is updated from the App Store some small number of the users get a new identifierForVendor for some reason. My users don't sign up or login. They are all anonymous so I need to separate them through their vendor IDs.
I've considered that there could've been insufficient space on some devices, resulting in the app being deleted and reinstalled, but that's not the case since in the last update a friend of mine had over 2GB of empty space.
I know that the identifierForVendor is changed for a user who deletes and reinstalls the app. But that's not the case here, as the app is just updated.
What could the problem be? The weird part is that this hasn't happened for development team devices yet. Or there are still users who haven't experienced this bug after countless app updates, OS updates, etc. This only happens to a small percentage of the users. All users are iOS7+ and it happens for different device models and iOS versions.
I use this code to get their ID:
static let DeviceId = UIDevice.currentDevice().identifierForVendor.UUIDString
Then I save them into NSUserDefaults:
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "User" + DeviceId)
NSUserDefaults.standardUserDefaults().synchronize()
Then I check if the user exists, at every new login:
static func doesUserExist() -> Bool {
var userDefaultValue: AnyObject? = NSUserDefaults.standardUserDefaults().valueForKey("User" + DeviceId)
if defaultValue == true {
println("Userdefaults already has this guy, moving on")
FirstTime = false
return true
} else {
println("First time in the app!")
FirstTime = true
return false
}
}
If the user does exist it starts the login process. If the user does not exist it shows them the signup process. I am using Parse.com as backend and the deviceID is used as a username. When that small amount of users experience this bug, I see a new username and a new account created.
There was a bug affecting the calculation of identifierForVendor when updating an app from app store between May and July. Apple has claimed they have already solved the issue and pushing another update should restore the original value before the critical date.
Reference: https://openradar.appspot.com/22677034
Take note that some users still have observed this issue even updating weeks after July. So it is still possible that bug is still there for some or it could resurface anytime in the future. So if you are using this data as part of your encryption, best is to save this to the keychain.
Save the vendorID in the KeyChain, that will persist after deletion or any update.
-(NSString *)getUniqueDeviceIdentifierAsString
{
NSString *appName=[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey];
NSString *strApplicationUUID = [SSKeychain passwordForService:appName account:#"incoding"];
if (strApplicationUUID == nil)
{
strApplicationUUID = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
[SSKeychain setPassword:strApplicationUUID forService:appName account:#"incoding"];
}
return strApplicationUUID;
}
Disclaimer: I took the code from some other SO answer a while ago, so
I don't remember whom to praise, but in the end it's not me
#Jonny found the source
I'm confused why you're saving the IFV to NSUserDefaults first and then checking to see if that key exists. I think you should...
1) check NSUserDefaults first to see if the IFV key you created exists
2) if NSUserDefaults key does exist, great do what you need with it, this user's profile already exists
3) if key does not exist, get the IFV and save it to NSUserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults valueForKey:#"IFV"]) {
//this user already exists, do what you need to do next with IFV
}
else{
//this is their first time using the app
NSString *ifvString = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
[defaults setValue:ifvString forKey:#"IFV"];
//do what you need to do next with IFV
}

How do I store & access a Twitter Fabric login session (iOS/Swift)?

I'm able to log in to Twitter through my app using this Twitter Fabric code:
let logInButton = TWTRLogInButton(logInCompletion: {
(session: TWTRSession!, error: NSError!) in
// play with Twitter session
if (session != nil) {
println("signed in as \(session.userName)");
self.TWUsernameLabel.text = "Logged in as #" + session.userName
} else {
println("error: \(error.localizedDescription)");
}
})
When I click the login button, it prompts me to approve the login and then logs me in, or it knows I already approved the login and it logs me in. This works like a charm and took all of ten minutes to set up. Amazing.
I already have an email-based login to access the app. I'd like to store a user's logged in Twitter account in that same database, so when a user logs in with their email, I already know their Twitter (if they have logged in before) and they don't need to log in again. The reason I do the email login is because Twitter is an important feature in my app, but not a total requirement.
The issue is that I have no idea how to access session outside of when the button is clicked and logInCompletion fires, and I don't know what variables to store upon initial login/check upon using the app.
I've read through the Twitter Fabric documentation numerous times, but it isn't written in swift, so it's pretty confusing. Any ideas? Thanks
If there is currently an active session you should be able to access it just like the docs say to
Twitter.sharedInstance().session()
If the user isn't logged in that method will return nil. If you want to know if someone is already authenticated just check to see if that method returns a value or not.
Twitter kit automatically present a login screen if user has not logged in (no session exist..).
But, before calling any future API, just check whether session is valid or not. In some APIs, you may required to pass this session too.
if ([[Twitter sharedInstance] session]) {
TWTRShareEmailViewController *shareEmailViewController =
[[TWTRShareEmailViewController alloc]
initWithCompletion:^(NSString *email, NSError *error) {
NSLog(#"Email %# | Error: %#", email, error);
}];
[self presentViewController:shareEmailViewController
animated:YES
completion:nil];
} else {
// Handle user not signed in (e.g. attempt to log in or show an alert)
}
}
You even don't need to worry about storing and managing access token and access token secret.
To access the authToken, userName or the userID for the logged in user session in Swift 4 is:
Twitter.sharedInstance().logIn(completion: { (session, error) in
if (session != nil) {
print(session!.authToken)
print(session!.userName)
print(session!.userID)
} else {
print(error?.localizedDescription)
}
})

How to detect if a Facebook access token has been refreshed?

in my app I need to detect if an access token has been refreshed so that i can update my API with the new token.
I am having trouble trying to figure out the best way to approach this since the Facebook SDK automatically caches the access token - currently I am comparing the old token (which i save to NSUserDefaults) with the accessToken of the activeSession's accessTokenData.
If the tokens are different I send update my api with the newer token.
here is my code within applicationWillEnterForeground
NSString *newToken = [FBSession activeSession].accessTokenData.accessToken;
NSString *oldToken = [[NSUserDefaults standardUserDefaults]valueForKey:#"accessToken"];
if (oldToken) {
if ([newToken isEqualToString:oldToken]) {
NSLog(#"token was not refreshed");
} else {
NSLog(#"token was refreshed");
[[NSUserDefaults standardUserDefaults]setValue:newToken forKey:#"accessToken"];
/* update API with new token*/
}
} else+
{
//if no token exists, set one with the current token
[[NSUserDefaults standardUserDefaults]setValue:newToken forKey:#"accessToken"];
}
I have to admit it's really hacky, but I cant seem to find a way around it. Is there any better way of approaching it?

Resources