I have the following in my AppDelegate
//added these 3 methods
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
window?.makeKeyAndVisible()
GIDSignIn.sharedInstance()?.clientID = Environment.googleClientId
FirebaseApp.configure()
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions);
let adjustAppToken = Environment.adjustToken
var environment = ADJEnvironmentSandbox
if (Environment.environment == "prod") {
environment = ADJEnvironmentProduction
}
let adjustConfig = ADJConfig(
appToken: adjustAppToken,
environment: environment)
adjustConfig?.logLevel = ADJLogLevelVerbose
adjustConfig?.delayStart = 2.5
adjustConfig?.delegate = self
Adjust.appDidLaunch(adjustConfig)
var configFlurryAPIKey = "x";
if (!isDev) {
configFlurryAPIKey = "x";
}
FlurryMessaging.setAutoIntegrationForMessaging()
// Step2 : (Optional) Get a callback
FlurryMessaging.setMessagingDelegate(self)
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0"
// Step3 : Start Flurry session
let builder = FlurrySessionBuilder.init()
.withAppVersion(version)
.withIncludeBackgroundSessions(inMetrics: true)
.withCrashReporting(true)
.withSessionContinueSeconds(10)
.withLogLevel(FlurryLogLevelAll)
Flurry.startSession(configFlurryAPIKey, with: builder)
// registerForPushNotifications()
Purchases.debugLogsEnabled = true
Purchases.configure(withAPIKey: Environment.revenueCatKey)
Amplitude.instance().trackingSessionEvents = true
// Initialize SDK
let amplitudeKey = Environment.amplitudeKey
Amplitude.instance().initializeApiKey(amplitudeKey)
if #available(iOS 14, *) {
print("status notDetermined == \(ATTrackingManager.trackingAuthorizationStatus == .notDetermined)")
print("status authorized == \(ATTrackingManager.trackingAuthorizationStatus == .authorized)")
print("IDFA == \(ASIdentifierManager.shared().advertisingIdentifier)")
ATTrackingManager.requestTrackingAuthorization { (status) in
var statusStr = "";
if (status == .authorized) {
statusStr = "authorized"
} else if (status == .denied) {
statusStr = "denied"
} else {
statusStr = "restricted"
}
let identify = AMPIdentify().set("att", value: statusStr as NSObject)
Amplitude.instance().identify(identify!)
}
}
Even though I'm calling App Transparency, Apple Review sent me this message
Starting with iOS 14.5, apps on the App Store need to receive the user’s permission through the AppTrackingTransparency framework before collecting data used to track them. This requirement protects the privacy of App Store users.
Next Steps
Here are two ways to resolve this issue:
If you do not currently track, or decide to stop tracking, update your app privacy information in App Store Connect. You must have the Account Holder or Admin role to update app privacy information.
If you track users, you must implement App Tracking Transparency and request permission before collecting data used to track. When you resubmit, indicate in the Review Notes where the permission request is located.
Does anyone know what I'm doing wrong?
You can follow this link to know how to update AppStore privacy if your app does not tracking user for third-party service purpose, otherwise you must implement App Transparency framework.
App Store Rejection - Guideline 5.1.2 - Legal - Privacy - Data Use and Sharing
Related
My app has got the option to allow its sound to be mixed with other apps.
According to Apple, MPRemoteCommandCenter is only available when apps do not allow for mixing.
Inside my app, when the user taps the button to change the mixWithOthers setting, the audio session is set accordingly.
However, even when the user switches back to not allow mixing anymore MPRemoteCommandCenter will not show up in lock screen until the app has been removed from cache (swiped up) and started again.
Is there a way to achieve the desired behaviour without having to re-start the app?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
UIApplication.shared.beginReceivingRemoteControlEvents()
}
var isMixWithOthersAllowed: Bool
func startProcess() {
setAudioSession {
setupMediaControls()
}
}
func setAudioSession(completion: #escaping () -> Void) {
let audioSession = AVAudioSession.sharedInstance()
do {
if isMixWithOthersAllowed {
try audioSession.setCategory(.playback, options: [.mixWithOthers])
/* The remote command center will not be available when mixing with others,
as stated by Apple in the docs. */
} else {
try audioSession.setCategory(.playback)
/* The remote command center should be available when switching back to
this category, but it will only show up after the app has been killed
and started fresh again. I'd like it to be available without restarting
the application. */
}
try audioSession.setActive(true)
} catch let error as NSError {
configureAudioSessionError = error
}
assert(configureAudioSessionError == nil, "Create audio session failed")
completion()
}
func setupMediaControls() {
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.isEnabled = true
commandCenter.pauseCommand.isEnabled = true
commandCenter.nextTrackCommand.isEnabled = true
commandCenter.previousTrackCommand.isEnabled = true
// Setup handlers for commands
// ...
setupNowPlaying()
}
func setupNowPlaying() {
// Configure audio track metadata and update UI elements
}
I am a beginner. I am developing an app with swift. I am using Firebase for signin. But I was wondering if I need to write codes to check user's sign-in status for each viewController for security. Or sign-in is needed only for the sign-in viewController like locking just a front door. My code may not be needed but below is the code that I wrote:
// Mark: User Sign-in Status Recheck
Auth.auth().addStateDidChangeListener { auth, user in
if user != nil {
if let user = user {
let userUid = user.uid
let userEmail = user.email
}
} else {
let InitialSignInFirstViewController = self.storyboard?.instantiateViewController(withIdentifier: "SignInFirstViewController") as! InitialSignInViewController
self.present(SignInFirstViewController, animated: false, completion: nil)
}
}
In my app I have a swift page that checks if the user is signed in when the app loads. If they are signed in they continue to the app, and you don't need to check until the app quits, and opens again. If they aren't signed in they go to another view controller to get signed in.
You don't need to manage the state or run the listener, there is more simpler way to do that, i.e.,
if Auth.auth().currentUser != nil {
// User is signed in.
// ...
} else {
// No user is signed in.
// ...
}
Update
You can create one class which just provide the user sign in status like below:
struct UserSignInStatus {
var isLoggedIn: Bool {
return (Auth.auth().currentUser != nil)
}
}
Usage: UserSignInStatus.isLoggedIn
You can put this code any where like in your AppDelegate class where you check the signin status and depending on that managing your rootViewController. Let me know if you need any more help.
I am developing an app in swift, and I use AWS mobile services for authentication and AWS Lambda to do some backend processing. I had everything working fine, and one day (after leaving the app for a month or so), it started throwing this error:
GetId failed. Error is [Error Domain=com.amazonaws.AWSCognitoIdentityProviderErrorDomain Code=-1000 "Authentication delegate not set" UserInfo {NSLocalizedDescription=Authentication delegate not set}]
Unable to refresh. Error is [Error Domain=com.amazonaws.AWSCognitoIdentityProviderErrorDomain Code=-1000 "Authentication delegate not set"
It's killing me, because it was already working. What could have changed?
In appDelegate, I have:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
// Uncomment to turn on logging, look for "Welcome to AWS!" to confirm success
AWSDDLog.add(AWSDDTTYLogger.sharedInstance)
AWSDDLog.sharedInstance.logLevel = .error
// Instantiate AWSMobileClient to get AWS user credentials
return AWSMobileClient.sharedInstance().interceptApplication(application, didFinishLaunchingWithOptions:launchOptions)
}
It actually throws the error before I make any invocation, so I think the lines above may be triggering the problem?
To login, I do the following, in my main viewController:
override func viewDidLoad() {
super.viewDidLoad()
if !AWSSignInManager.sharedInstance().isLoggedIn {
presentAuthUIViewController()
}
else{
getCredentials()
}
...
}
func presentAuthUIViewController() {
let config = AWSAuthUIConfiguration()
config.enableUserPoolsUI = true
config.backgroundColor = UIColor.white
config.logoImage = #imageLiteral(resourceName: "logoQ")
config.isBackgroundColorFullScreen = true
config.canCancel = true
AWSAuthUIViewController.presentViewController(
with: self.navigationController!,
configuration: config, completionHandler: { (provider:
AWSSignInProvider, error: Error?) in
if error == nil {
self.getCredentials()
} else {
// end user faced error while loggin in, take any required action here.
}
})
}
func getCredentials() {
let serviceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: nil)
let userPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: "id",
clientSecret: "secret",
poolId: "id")
AWSCognitoIdentityUserPool.register(with: serviceConfiguration, userPoolConfiguration: userPoolConfiguration, forKey: "key")
let pool = AWSCognitoIdentityUserPool(forKey: "key")
if let username = pool.currentUser()?.username {
userName = username
}
It loggs in, and I retrieve the user name.
Any tips? I followed some of the instructions in other posts but they didn't work, plus what most disconcerts me is that it was working!
Thanks in advance
I think this means that your refresh token expired.
So, not 100% sure of what was going on, but as I understand it there was a problem with the credentials for the user in the user pool. I reset the password and all started working fine again!
If anyone needs more details just ask, and if anyone understands this better let me know..
I build chat app. I have field in each user table which allow to check if user Online. I use just database reference to get isOnline status and update it when pull to refresh. I seen that apps update online status automatically when user open or fold app. How i can do that? Do i need any listener or any framework can help me upgrade my code)) Something like ReactiveCocoa/ReactiveSwift...
P.S sorry for cyrillic text on field isOnline) it means Online/Offline
When application start you can update user online in AppDelegate
Update user online
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
// status parameter indicate user Online
if Auth.auth().currentUser != nil {
OnlineOfflineService.online(for: (Auth.auth().currentUser?.uid)!, status: true){ (success) in
print("User ==>", success)
}
}
return true
}
Update user Offline
func applicationWillTerminate(_ application: UIApplication) {
if Auth.auth().currentUser != nil {
OnlineOfflineService.online(for: (Auth.auth().currentUser?.uid)!, status: false){ (success) in
print("User ==>", success)
}
}
}
Firebase online and offline update service
import UIKit
import FirebaseDatabase
struct OnlineOfflineService {
static func online(for uid: String, status: Bool, success: #escaping (Bool) -> Void) {
//True == Online, False == Offline
let onlinesRef = Database.database().reference().child(uid).child("isOnline")
onlinesRef.setValue(status) {(error, _ ) in
if let error = error {
assertionFailure(error.localizedDescription)
success(false)
}
success(true)
}
}
}
Also you need to take care about user network connection. If user network connection off you just call OnlineOfflineService with parameters
I know this is an older question, but if you want to set the online/offline value to false when user closes app, use .onDisconnectSetValue():
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
setInactivityObservers()
return true
}
func setInactivityObservers() {
guard let user = Auth.auth().currentUser else { return }
// get user branch of database
let ref = Database.database().reference()
let usersRef = ref.child("Users")
let userRef = usersRef.child(user.uid)
// set "isOnline" branch to true when app launches
userRef.child("isOnline").setValue(true)
// set value to false when user terminates app
userRef.child("isOnline").onDisconnectSetValue(false)
}
First
Database.database().isPersistenceEnabled = true
Then manage the "presence"
let presenceRef = Database.database().reference(withPath: "disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnectSetValue("I disconnected!")
Then when the user is disconnected
presenceRef.onDisconnectRemoveValue { error, reference in
if let error = error {
print("Could not establish onDisconnect event: \(error)")
}
}
And Finally, to detect the status
let connectedRef = Database.database().reference(withPath: ".info/connected")
connectedRef.observe(.value, with: { snapshot in
if snapshot.value as? Bool ?? false {
print("Connected")
} else {
print("Not connected")
}
})
Is it ok now ?
This is pretty straight forward. I am trying to execute a function that triggers the pre-filling of data. However at the end of the function it dies. I am executing all of this within the AppDelegate file.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
// Override point for customization after application launch.
let initialize = Initialize()
// Check to see if the application ID exists
if (NSUserDefaults.standardUserDefaults().objectForKey("appId") == nil ){
// Refresh the info
self.preload()
println("Data Preload Completed")
} else {
// running anyways to trigger the error.
self.preload()
println("Data Already Preloaded")
}
return true
}
func preload()->Bool {
// Preload static data for the app.
var conditions = Conditions()
conditions.preloadData()
var imageTypes = ImageTypes()
imageTypes.preloadData()
var propertyTypes = PropertyTypes()
propertyTypes.preloadData()
//Save the appId 58AEF58E-2794-4F60-B0A6-0FAB4A943811
NSUserDefaults.standardUserDefaults().setObject("58AEF58E-2794-4F60-B0A6-0FAB4A943811", forKey: "appId")
NSUserDefaults.standardUserDefaults().synchronize()
println(NSUserDefaults.standardUserDefaults().dictionaryRepresentation())
return true
}
I am not sure if this "The" answer to the issue, but I had to delete all of the Simulator profiles, and for each device hit [iOS Simulator].[Reset Content & Settings] and then hit the "Reset" button to confirm. I suspect that somewhere along the way I corrupted the plist file that NSUserDefaults connects to.