I am trying to add in-app purchases to my iOS app. I followed a tutorial and I created the following code:
import UIKit
import StoreKit
let secondViewController: SKStoreProductViewController = SKStoreProductViewController();
class GameViewController: UIViewController, UITextFieldDelegate, GKGameCenterControllerDelegate, SKStoreProductViewControllerDelegate{
func buycoin(){
println("buycoin")
secondViewController.delegate = self
var someitunesid:String = "coin200a"
var productparameters = [SKStoreProductParameterITunesItemIdentifier: someitunesid]
secondViewController.loadProductWithParameters(productparameters, {
(success:Bool!, error: NSError!) -> Void in
if success == true{
self.presentViewController(secondViewController, animated: true, completion: nil)
println("succes")
}
else{
NSLog("%#", error)
println("nosucces")
}
})
}
func productViewControllerDidFinish(viewController: SKStoreProductViewController!) {
secondViewController.dismissViewControllerAnimated(true, completion: nil)
}
}
This code works fine. When the function buycoin() activates, I only get printed buycoin in the console, nothing else.
What am I doing wrong?
Related
I am working on implementing Interstitial ads in my app and running into some confusion with the docs provided by Admob and the new SwiftUI app structure.
Here is the app.swift file, showing that I've implemented the GoogleMobileAds and started it in the didFinishLaunchingWithOptions method.
import SwiftUI
import GoogleMobileAds
#main
struct adamsCalcApp: App {
var calculator = Calculator()
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView().environmentObject(calculator)
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// Setup google admob instance
GADMobileAds.sharedInstance().start(completionHandler: nil)
return true
}
}
In my ContentView.swift File, I have the interstitial variable created like...
#State var interstitial: GADInterstitialAd?
Then on the main stack in the view, I call onAppear(perform: ) to load the ad, however I keep getting this error.
.onAppear(perform: {
let request = GADRequest()
GADInterstitialAd.load(withAdUnitID:"ca-app-pub-3940256099942544/4411468910",
request: request,
completionHandler: { [self] ad, error in
if let error = error {
return
}
interstitial = ad
interstitial?.fullScreenContentDelegate = self
}
)
})
"Cannot assign value of type 'ContentView' to type
'GADFullScreenContentDelegate?'"
I am feeling a bit clueless after trying a few different workarounds and trying to look up a setup that is like mine, AdMob docs still show how to implement with class ViewControllers and I would like to figure out how to do this is SwiftUI.
import SwiftUI
import GoogleMobileAds
import AppTrackingTransparency
import AdSupport
class AdsManager: NSObject, ObservableObject {
private struct AdMobConstant {
static let interstitial1ID = "..."
}
final class Interstitial: NSObject, GADFullScreenContentDelegate, ObservableObject {
private var interstitial: GADInterstitialAd?
override init() {
super.init()
requestInterstitialAds()
}
func requestInterstitialAds() {
let request = GADRequest()
request.scene = UIApplication.shared.connectedScenes.first as? UIWindowScene
ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in
GADInterstitialAd.load(withAdUnitID: AdMobConstant.interstitial1ID, request: request, completionHandler: { [self] ad, error in
if let error = error {
print("Failed to load interstitial ad with error: \(error.localizedDescription)")
return
}
interstitial = ad
interstitial?.fullScreenContentDelegate = self
})
})
}
func showAd() {
let root = UIApplication.shared.windows.last?.rootViewController
if let fullScreenAds = interstitial {
fullScreenAds.present(fromRootViewController: root!)
} else {
print("not ready")
}
}
}
}
class AdsViewModel: ObservableObject {
static let shared = AdsViewModel()
#Published var interstitial = AdsManager.Interstitial()
#Published var showInterstitial = false {
didSet {
if showInterstitial {
interstitial.showAd()
showInterstitial = false
} else {
interstitial.requestInterstitialAds()
}
}
}
}
#main
struct YourApp: App {
let adsVM = AdsViewModel.shared
init() {
GADMobileAds.sharedInstance().start(completionHandler: nil)
}
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(adsVM)
}
}
Toggle the showInterstitial parameter in the AdsViewModel anywhere in the application and the advertisement will be shown.
In order to use the Admob docs with the newest SwiftUI release, you need to change this line...
.onAppear(perform: {
let request = GADRequest()
GADInterstitialAd.load(withAdUnitID:"ca-app-pub-3940256099942544/4411468910",
request: request,
completionHandler: { [self] ad, error in
if let error = error {
return
}
// Change these two lines of code
interstitial = ad
interstitial?.fullScreenContentDelegate = self
// To...
interstitial = ad
let root = UIApplication.shared.windows.first?.rootViewController
self.interstitial!.present(fromRootViewController: root!)
}
)
})
I'm testing my parse code on Heroku because of parse.com's shutdown. In Swift 3, saveInBackgroundWithBlock has been renamed to saveInBackground, so I updated that syntax in my code as well as the 'NS' prefix issue. But an error still remains. As a learner, I can't possibly take care of this further. I want a kind person to help me solve this. Thanks in advance.
import UIKit
import Parse
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let object = PFObject(className: "testObject")
object["name"] = "Bill"
object["lastname"] = "Alexander"
object.saveInBackground(block: { (success, error) in
if success {
print("Saved in server")
} else {
print(error!)
}
})
}
Here is also my screenshot:
'Expected declaration' error screenshot
You almost there, The syntax is just slightly incorrect. Also check against the error for any issues.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let object = PFObject(className: "testObject")
object["name"] = "Bill"
object["lastname"] = "Alexander"
object.saveInBackground { (success, error) -> Void in
if error == nil {
print("Saved in server")
} else {
print(error!)
}
}
}
I am trying to migrate to swift 2.0 but not all of my code is working. I have succed to migrate most of the code but I stillt have troubles using the EventKit. The code below was working fine with swift 1.2. But now I have a Problem
import Foundation
import EventKit
import Cocoa
private let _SingletonSharedInstance = EventStore()
class EventStore {
let eventStore = EKEventStore ()
class var sharedInstance : EventStore {
return _SingletonSharedInstance
}
init() {
var sema = dispatch_semaphore_create(0)
var hasAccess = false
eventStore.requestAccessToEntityType(EKEntityTypeEvent, completion: { (granted:Bool, error:NSError?) in hasAccess = granted; dispatch_semaphore_signal(sema) })
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)
if (!hasAccess) {
println("ACCESS", "ACCESS LONG")
let sharedWorkspace = NSWorkspace.sharedWorkspace()
sharedWorkspace.openFile("/Applications/System Preferences.app")
exit (0)
}
}
}
Following line is causing the Problems
eventStore.requestAccessToEntityType(EKEntityTypeEvent, completion: { (granted:Bool, error:NSError?) in hasAccess = granted; dispatch_semaphore_signal(sema) })
I am getting the error
cannot invoke "requestAccessToEntityType" with an argument list of type '(EKEEntityType, completion: (Bool, NSError?) -> ())'
I read that using NSError! should solve the issue but it did not.
Any ideas?
I found the answer. The bool type had changed to ObjCBool and EKEntityTypeEvent to EKEntityType.Event.
import Foundation
import EventKit
import Cocoa
private let _SingletonSharedInstance = EventStore()
class EventStore {
let eventStore = EKEventStore ()
class var sharedInstance : EventStore {
return _SingletonSharedInstance
}
init() {
var sema = dispatch_semaphore_create(0)
var hasAccess:ObjCBool = false
eventStore.requestAccessToEntityType(EKEntityType.Event, completion: { (granted:ObjCBool, error:NSError?) in hasAccess = granted; dispatch_semaphore_signal(sema) })
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)
if (!hasAccess) {
println("ACCESS", "ACCESS LONG")
let sharedWorkspace = NSWorkspace.sharedWorkspace()
sharedWorkspace.openFile("/Applications/System Preferences.app")
exit (0)
}
}
}
With Swift 2, GameCenter is not working for me. The authentication ViewController is not showing up... Here is my func authenticateLocalPlayer():
func authenticateLocalPlayer() {
var localPlayer = GKLocalPlayer()
localPlayer.authenticateHandler = {(viewController: UIViewController?, error: NSError?) -> Void in
if (viewController != nil) {
self.presentViewController(viewController!, animated: true, completion: nil)
print("Not Authenticated. ")
} else {
print("Authenticated. ")
}
}
}
It is returning "Not Authenticated" every time, but is not presenting the ViewController. Any solution?
This solution presents the viewController correctly using Swift 2 in Xcode 7.0.
Note that I have changed the code before the if statement begins. I believe the syntax may have changed in a recent software update as I had this problem too.
In my app I called authenticateLocalPlayer() in the viewDidLoad() method of the GameViewController class.
func authenticateLocalPlayer() {
let localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if (viewController != nil) {
self.presentViewController(viewController!, animated: true, completion: nil)
}
else {
print((GKLocalPlayer.localPlayer().authenticated))
}
}
}
I am trying to make that when the user press Facebook button, it opens the Facebook application, or in browser.
Import code:
import Foundation
Extension code:
extension UIApplication {
class func tryURL(urls: [String]) {
let application = UIApplication.sharedApplication()
for url in urls {
if application.canOpenURL(NSURL(string: url)!) {
application.openURL(NSURL(string: url)!)
return
}
}
}
}
Function code:
func fimageTapped()
{
UIApplication.tryURL([
"fb://profile/1357163924", // App
"http://www.facebook.com/1357163924" // Website if app fails
])
}
I get error at line:
class func tryURL(urls: [String]) {
Error message:
Invalid redeclaration of "tryURL"
This is where i found the code from: Xcode swift link to facebook page
Anyone has any idea what is wrong here?
In Swift 3 use this:
let facebookID: String = "000000000000"
let facebookName: String = "name"
let facebookURLID = URL(string: "fb://profile/\(facebookID)")!
let facebookURLWeb = URL(string: "https://m.facebook.com/\(facebookName)?id=\(facebookID)")!
if(UIApplication.shared.canOpenURL(facebookURLID)){
UIApplication.shared.openURL(facebookURLID)
} else {
UIApplication.shared.openURL(facebookURLWeb)
}
Remember that from iOS 9 and 10 you need to declare in the Info.plist:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fb</string>
</array>
With this the queries for the Facebook schemes will not fail with a permission error:
"This app is not allowed to query for scheme fb"
Used this, worked fine:
var fbURLWeb: NSURL = NSURL(string: "https://www.facebook.com/ID")!
var fbURLID: NSURL = NSURL(string: "fb://profile/ID")!
if(UIApplication.sharedApplication().canOpenURL(fbURLID)){
// FB installed
UIApplication.sharedApplication().openURL(fbURLID)
} else {
// FB is not installed, open in safari
UIApplication.sharedApplication().openURL(fbURLWeb)
}
Swift 3:
Important: UIApplication is declared in UIKit so make sure you import UIKit aswell.
import Foundation
import UIKit
extension UIApplication {
class func tryURL(_ urls: [String]) {
let application = UIApplication.shared
for url in urls {
if application.canOpenURL(URL(string: url)!) {
application.open(URL(string: url)!, options: [:], completionHandler: nil)
return
}
}
}
}
Furthermore:
application.openURL(NSURL(string: url)!)
have in Swift 3 changed to open and with completionHandler:
application.open(URL(string: url)!, options: [:], completionHandler: nil)
Next in your viewController: declare your facebook app and web-urls above viewDidLoad and create a function or IBAction func where you do your UIapplication.tryURL:
import UIKit
class ViewController: UIViewController {
let fbAppUrl = "facebook://profile/yourFBprofileID"
let fbWebUrl = "https://www.facebook.com/yourFBprofileID"
override func viewDidLoad() {
super.viewDidLoad()
}
func openFacebook() {
UIApplication.tryURL([fbAppUrl, fbWebUrl])
}
}
First iOS will try to open the fbAppUrl but if the facebook app is not installed on the device it will open fbWebUrl in Safari instead.
For Swift 4
let webURL: NSURL = NSURL(string: "https://www.facebook.com/ID")!
let IdURL: NSURL = NSURL(string: "fb://profile/ID")!
if(UIApplication.shared.canOpenURL(IdURL as URL)){
// FB installed
UIApplication.shared.open(webURL as URL, options: [:], completionHandler: nil)
} else {
// FB is not installed, open in safari
UIApplication.shared.open(webURL as URL, options: [:], completionHandler: nil)
}