iOS IAP Restore needs few tries - ios

I encounter a really awkward behavior of in app purchases in my app.
The app is a webview, so I created a webview and load my local HTML files.
Since my last update, the IAP Restore now needs several tries until it finally restores the specific product. I have 3 products and I noticed that my first IAP needs 1-2 tries until it restores, but the other 2 restore only after I try restore 3-4-5-6-7 times.
Nothing changed in restore code in the last update, and I did not find any clue anywhere in other found questions.
And a second question:
If I purchased all 3 products, should restoring one product restore all of them?
UPDATE:
Here is my code
func restorePurchases() {
NetworkActivityIndicatorManager.networkOperationStarted()
SwiftyStoreKit.restorePurchases(atomically: true) { results in
NetworkActivityIndicatorManager.networkOperationFinished()
for purchase in results.restoredPurchases {
let downloads = purchase.transaction.downloads
if !downloads.isEmpty {
SwiftyStoreKit.start(downloads)
} else if purchase.needsFinishTransaction {
// Deliver content from server, then:
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
}
self.showAlert(self.alertForRestorePurchases(results))
}
}
func alertForRestorePurchases(_ results: RestoreResults) -> UIAlertController {
if results.restoreFailedPurchases.count > 0 {
print("Restore Failed: \(results.restoreFailedPurchases)")
return alertWithTitle("Restore succesful", message: "Everything was restored.")
} else if results.restoredPurchases.count > 0 {
print("Restore Success: \(results.restoredPurchases)")
var isSuccess = false
for i in 0 ..< results.restoredPurchases.count
{
let pId = results.restoredPurchases[0].productId
if pId == self.currentProductId
{
isSuccess = true
if(pId == appDelegate.pId1)
{
UserDefaultManager.setPurchaseStatus(flag: true)
self.purchaseTimer.invalidate()
}
else if(pId == appDelegate.pId2)
{
UserDefaultManager.setPicaPurchaseStatus(flag: true)
self.purchaseTimer.invalidate()
}
else if(pId == appDelegate.pId3)
{
UserDefaultManager.setPicaRealPurchaseStatus(flag: true)
self.purchaseTimer.invalidate()
}
makeJsScriptCall()
return alertWithTitle("Activated!", message: "Everything was restored!")
}
}
if(!isSuccess)
{
return alertWithTitle("Something went wrong", message: "This is the error that I get until I try restore 3-4 times")
}
func showPurchaseActionSheet() {
let alert = UIAlertController(title: "Choose Option", message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Purchase", style: .default , handler:{ (UIAlertAction)in
self.purchase(.nonConsumablePurchase, atomically: true)
}))
alert.addAction(UIAlertAction(title: "Restore", style: .default , handler:{ (UIAlertAction)in
self.restorePurchases()
}))
alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler:{ (UIAlertAction)in
}))
alert.popoverPresentationController?.sourceView = self.view
self.present(alert, animated: true, completion: {
print("completion block")
})
}

Related

Stop a executing a function when if statement returns true

I have an app that allows users to save their profile. In order for them to be able to sign up, I want to check and see if they have agreed to the apps terms and conditions. The issue I am having is if the user doesn't agree to them, they will see an alertController telling them to agree. However, the app still continues to execute the remainder of the code.
func checkIfChecked() {
if self.checkbox.imageView.isHidden == true {
let alert = UIAlertController(title: "Hold up!",message:" You must agree to our Community Guidelines before you can sign up.", preferredStyle: UIAlertController.Style.alert)
let continueButton = UIAlertAction(title: "Got it!", style: .default, handler: {(_ action: UIAlertAction) -> Void in
})
continueButton.setValue(GREEN_Theme, forKey: "titleTextColor")
alert.addAction(continueButton)
self.present(alert, animated: true, completion: nil)
}
if self.checkbox2.imageView.isHidden == true {
let alert = UIAlertController(title: "Hold up!",message:" You must agree to our Terms & Conditions before you can sign up.", preferredStyle: UIAlertController.Style.alert)
let continueButton = UIAlertAction(title: "Got it!", style: .default, handler: {(_ action: UIAlertAction) -> Void in
})
continueButton.setValue(GREEN_Theme, forKey: "titleTextColor")
alert.addAction(continueButton)
self.present(alert, animated: true, completion: nil)
}
}
#objc func handleRegister() {
checkIfChecked()
let hud = JGProgressHUD(style: .dark)
hud.textLabel.text = "Registering!"
hud.show(in: view)
guard let email = emailTextField.text, let password = passwordTextField.text, let name = nameTextField.text, let phonenumber = phonenumberTextField.text else {
print("Error")
return
the remainder of code....
}
}
if the checkBoxs are checked, there is no issue. But if they are not checked, then the users information will still be saved to the data base without them logging in. So I am trying to stop the execution of handleRegister after checkIfChecked is called only if the boxs were not checked.
Not sure if this is the safest way to fix the issue I am having, but what I did to fix the problem is inside of of the handleRegister, I added
checkIfChecked()
this has to be after the checkIfChecked that way the alertControllers can show.
if self.checkbox.imageView.isHidden == true {
return
} else if self.checkbox2.imageView.isHidden == true {
return
}
it does stop the execution of code if these lines are true.

RPScreenRecorder not recording mic in odd situations

Why won't RPScreenRecorder record the mic, even though it is enabled, if the permissions popup doesn't appear? It works when the popup appears but attempts after restarting the app don't record the mic.
here's the very simple app i made just to test this feature for a larger app.
I have tested this exact application on iOS 11 and it works every time. However on iOS 12+ it only works when the permission popup appears and that's every 8 minutes. It should work every time after giving permissions.
import ReplayKit
class ViewController: UIViewController, RPPreviewViewControllerDelegate {
private let recorder = RPScreenRecorder.shared()
private var isRecording = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func react() {
if !isRecording {
let alert = UIAlertController(title: "Record", message: "Would you like to record a video?", preferredStyle: .alert)
let okay = UIAlertAction(title: "Okay", style: .destructive, handler: { (action: UIAlertAction) in
self.startRecording()
})
alert.addAction(okay)
self.present(alert, animated: true, completion: nil)
} else {
stopRecording()
}
}
private func startRecording() {
guard self.recorder.isAvailable else {
print("Recording is not available at this time.")
return
}
self.recorder.isMicrophoneEnabled = true
self.recorder.startRecording{ [unowned self] (error) in
guard error == nil else {
print("There was an error starting the recording.")
return
}
print("Started Recording Successfully")
self.isRecording = true
}
}
private func stopRecording() {
recorder.stopRecording { [unowned self] (preview, error) in
print("Stopped recording")
guard preview != nil else {
print("Preview controller is not available.")
return
}
let alert = UIAlertController(title: "Recording Finished", message: "Would you like to edit or delete your recording?", preferredStyle: .alert)
let deleteAction = UIAlertAction(title: "Delete", style: .destructive, handler: { (action: UIAlertAction) in
self.recorder.discardRecording(handler: { () -> Void in
print("Recording suffessfully deleted.")
})
})
let editAction = UIAlertAction(title: "Edit", style: .default, handler: { (action: UIAlertAction) -> Void in
preview?.previewControllerDelegate = self
self.present(preview!, animated: true, completion: nil)
})
alert.addAction(editAction)
alert.addAction(deleteAction)
self.present(alert, animated: true, completion: nil)
self.isRecording = false
}
}
func previewControllerDidFinish(_ previewController: RPPreviewViewController) {
dismiss(animated: true)
}
}
I expect that the mic should record every single time after allowing the permissions however it appears to only be recording the mic during the sessions in which it asks for those permissions.
This appears to have been fixed in iOS 13. The OS now asks for permission every time you request to record the screen. I still don't have a fix for iOS 12 however.

Restore purchase swift 4 programmatically

This problem occurs to me: Purchase a subscription through a movie with a lock. I click on the camera button. The subscription view opens. I make my purchase: I display an error message (but the purchase is still successful).
func subscribe(sub: SubscriptionType) {
DispatchQueue.main.async { let _ = MBProgressHUD.standardHud(over: self.managedView) }
FS2Recipes.subscribe(sku: sub.sku()).then { _ in
self.subscribed()
}.catch { error in
debugPrint("Error \(error.localizedDescription)")
let alert = UIAlertController(title: "Ooops", message: "There was an error processing your purchase. Try again later!", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak self] _ in
self?.dismiss()
}))
self.present(alert, animated: true, completion: nil)
}.always {
DispatchQueue.main.async { let _ = MBProgressHUD.hide(for: self.managedView, animated: true) }
}
}
Error

Check of Location permissions set

My iOS app has been rejected by Apple as the app crashes if a user selected "Dont allow" location access. And the proceeds to tap on my Map button.
How can I wrap this button in check to see if the user has given permission, And if not how can I ask for permission again?
//Map Button Action - Opens Maps - Gives choice of Google or Apple maps
#IBAction func googleMapBtn(_ sender: UIButton) {
UIDevice.current.isBatteryMonitoringEnabled = true
let state = UIDevice.current.batteryState
//If user is in Loop - Cant open maps
if state == .charging {
print("In Loop - Cant open maps")
}
//Present Map Options
else {
let alertController = UIAlertController.init(title: "Open Map", message: "", preferredStyle: .alert)
alertController.addAction(UIAlertAction.init(title: "Google Maps", style: .default, handler: { (action) in
self.googleMapsOpen()
}))
alertController.addAction(UIAlertAction.init(title: "Apple Maps", style: .default, handler: { (action) in
self.appleMapsOpen()
}))
alertController.addAction(UIAlertAction.init(title: "Back", style: .default, handler: { (action) in
self.dismiss(animated: true, completion: nil)
}))
self.present(alertController, animated: true) {
}
}
}
The code crashes whenever a user selects a map type Google/Apple and the self.googleMapsOpen() or self.appleMapsOpen() are executed. Specifically is crashed on the let scheme=
func googleMapsOpen(){
print("Google Maps Pressed")
let scheme = "comgooglemaps://?center=\(LocationManager.sharedInstance.location.coordinate.latitude),\(LocationManager.sharedInstance.location.coordinate.longitude)&zoom=15"
self.open(scheme: scheme)
}
func appleMapsOpen(){
print("Apple Maps Pressed")
let scheme = "http://maps.apple.com/?ll=\(LocationManager.sharedInstance.location.coordinate.latitude),\(LocationManager.sharedInstance.location.coordinate.longitude)&zoom=15"
self.open(scheme: scheme)
}
You can do something like this :
func checkLocationPermissionEnabled()
{
if CLLocationManager.locationServicesEnabled()
{
switch(CLLocationManager.authorizationStatus())
{
case .notDetermined, .restricted, .denied:
self.openDeviceLocationSetting()
return
case .authorizedAlways, .authorizedWhenInUse:
//do whatever you want to do with location
return
}
}
else
{
self.openDeviceLocationSetting()
return
}
}
func openDeviceLocationSetting()
{
let alertController = UIAlertController(title: "", message:"For best results, let your device turn on location using Google's location service.", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
UIAlertAction in
self.isAlertShowing = false
let settingsUrl = NSURL(string: UIApplicationOpenSettingsURLString)
if let url = settingsUrl {
UIApplication.shared.openURL(url as URL)
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default) {
UIAlertAction in
}
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}

how can I remove duplicate Contact with OK alert button?

how can I remove duplicate Contact from my table view when tap OK alert button?
Here's my findDuplicateContacts()
#objc fileprivate func findDuplicateContacts() {
let keys = [CNContactIdentifierKey as CNKeyDescriptor, CNContactFormatter.descriptorForRequiredKeys(for: .fullName)]
let request = CNContactFetchRequest(keysToFetch: keys)
var contactsByName = [String: [CNContact]]()
do {
try self.contactStore.enumerateContacts(with: request) { contact, stop in
guard let name = CNContactFormatter.string(from: contact, style: .fullName) else { return }
contactsByName[name] = (contactsByName[name] ?? []) + [contact] // or in Swift 4, `contactsByName[name, default: []].append(contact)`
}
} catch let err {
print("error:", err)
}
let duplicates = contactsByName.filter { $1.count > 1 }
let alert = UIAlertController(title: "Alert", message: "Number of duplicates: \(duplicates.count)", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: {(action:UIAlertAction!) in
//HERE I WANT TO REMOVE DUPLICATES
print("you have pressed the ok button")
}))
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
print(duplicates)
self.tableView.reloadData()
}
Thanks in advance for reply
You should use CNSaveRequest class func delete(_ contact: CNMutableContact) method, executing with func execute(_ saveRequest: CNSaveRequest) method of CNContactStore class
This example removes all other contacts and keeps only one (position 0) but you can add a method to determine which contact is more complete and keep that one
Full Code
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: {(action:UIAlertAction!) in
print("you have pressed the ok button")
var arrayOfContactsRequests : [CNSaveRequest] = []
for dict in duplicates {
for (index,contact) in dict.value.enumerated() {
if(index != 0) {
let saveRequest = CNSaveRequest()
saveRequest.delete(contact.mutableCopy() as! CNMutableContact)
arrayOfContactsRequests.append(saveRequest)
}
}
}
debugPrint(duplicates)
for request in arrayOfContactsRequests {
do{
try self.contactStore.execute(request)
}
catch let err {
print("error:", err)
}
}
}))
This answer was possible with help of this answer How to convert CNContact to CNMutableContact?

Resources