I'm trying to display an ad with GADAppOpenAd
The problem is, every initial login to the application, no advertisement is displayed, only when I go to the background and return to the application, then an advertisement appears,
I'm trying to have an advertisement appear on the initial login as well
var appOpenAd: GADAppOpenAd?
var loadTime = Date()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GADMobileAds.sharedInstance().start(completionHandler: nil)
requestAppOpenAd()
return true
}
extension AppDelegate:GADFullScreenContentDelegate {
func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
requestAppOpenAd()
}
func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
requestAppOpenAd()
}
func requestAppOpenAd() {
let request = GADRequest()
GADAppOpenAd.load(withAdUnitID: "ca-app-pub-3940256099942544/5662855259",
request: request,
orientation: UIInterfaceOrientation.portrait,
completionHandler: { (appOpenAdIn, _) in
self.appOpenAd = appOpenAdIn
self.appOpenAd?.fullScreenContentDelegate = self
self.loadTime = Date()
print("Ad is ready")
})
}
func tryToPresentAd() {
guard let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController else {
return
}
if let gOpenAd = self.appOpenAd, wasLoadTimeLessThanNHoursAgo(thresholdN: 4){
gOpenAd.present(fromRootViewController: rootViewController)
} else {
self.requestAppOpenAd()
}
}
func wasLoadTimeLessThanNHoursAgo(thresholdN: Int) -> Bool {
let now = Date()
let timeIntervalBetweenNowAndLoadTime = now.timeIntervalSince(self.loadTime)
let secondsPerHour = 3600.0
let intervalInHours = timeIntervalBetweenNowAndLoadTime / secondsPerHour
return intervalInHours < Double(thresholdN)
}
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func sceneDidBecomeActive(_ scene: UIScene) {
(UIApplication.shared.delegate as? AppDelegate)?.tryToPresentAd()
}
}
Related
BGAppRefreshTask is not working, I marked the option of background fetch capability
The method inside BGTaskScheduler.shared.register is never called
my code:
private let appRefreshTaskId = "internetDisconnectionsId"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 13, *) {
BGTaskScheduler.shared.register(forTaskWithIdentifier: appRefreshTaskId, using: nil) { task in
self.handleAppRefreshTask(task: task as! BGAppRefreshTask)
}
}
return true
}
func handleAppRefreshTask(task: BGAppRefreshTask) {
task.expirationHandler = {
print("Background Working")
task.setTaskCompleted(success: true)
}
}
#available(iOS 13.0, *)
func scheduleAppRefresh() {
let request = BGAppRefreshTaskRequest(identifier: appRefreshTaskId)
request.earliestBeginDate = Date(timeIntervalSinceNow: 2 * 60) // Refresh after 2 minutes.
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule app refresh task \(error.localizedDescription)")
}
}
func sceneDidEnterBackground(_ scene: UIScene) {
(UIApplication.shared.delegate as! AppDelegate).scheduleAppRefresh()
print("called")
}
I would love to understand where I am wrong
Guys, I need your help, please.
What do I need: to get the tag's UID using iOS app
What do I have: I have an app Flutter, which works fine on Android (I can read the tag's UID) and do nothing on iOS
Details:
I have this type of cards (plastic card)
card's data, Mifare Classis 1k
As you can see, this is the Mifare Classic 1k card with payload "My text with spaces"
I used flutter channels to communicate between flutter and iOS native (swift)
On iOS side I created two implementations: one for NFCTagReaderSession, another one for NFCNDEFReaderSession (I do not use it at the same time, only separated)
1. NFCTagReaderSession implementation
import UIKit
import Flutter
import CoreNFC
#available(iOS 13.0, *)
var session_tag: NFCTagReaderSession?
#available(iOS 13.0, *)
var flutterResult: FlutterResult!
#available(iOS 13.0, *)
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate, NFCTagReaderSessionDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let nfcChannel = FlutterMethodChannel(name: "samples.flutter.dev/nfc", binaryMessenger: controller.binaryMessenger)
nfcChannel.setMethodCallHandler({
[weak self] (call: FlutterMethodCall, result: #escaping FlutterResult) -> Void in
// Note: this method is invoked on the UI thread.
guard call.method == "getNFCTag" else {
result(FlutterMethodNotImplemented)
return
}
if NFCTagReaderSession.readingAvailable {
print("we are ready for reading");
self?.startReadingNFC(result: result)
} else {
print("sorry byt not working");
}
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func startReadingNFC(result: #escaping FlutterResult) {
flutterResult = result
session_tag = NFCTagReaderSession(pollingOption: .iso14443, delegate: self, queue: DispatchQueue.main)
session_tag?.alertMessage = "Hold ur phone!"
session_tag?.begin()
}
func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
print("Tag session active")
}
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
print("Did detect tag reader session")
print(tags.count)
if case let NFCTag.miFare(tag) = tags.first! {
session.connect(to: tags.first!) { (error: Error?) in
let tagUIDData = tag.identifier
var byteData: [UInt8] = []
tagUIDData.withUnsafeBytes { byteData.append(contentsOf: $0) }
session.invalidate()
print(self.hexEncodedString(byteArray: byteData))
// DispatchQueue.main.async {
//flutterResult(self.hexEncodedString(byteArray: byteData))
// }
}
}
}
func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
print("Tag Error: \(error.localizedDescription)")
}
func hexEncodedString(byteArray: [UInt8]) -> String {
let hexDigits = Array("0123456789abcdef".utf16)
var hexChars = [UTF16.CodeUnit]()
hexChars.reserveCapacity(byteArray.count * 2)
for byte in byteArray {
let (index1, index2) = Int(byte).quotientAndRemainder(dividingBy: 16)
hexChars.append(hexDigits[index1])
hexChars.append(hexDigits[index2])
}
return String(utf16CodeUnits: hexChars, count: hexChars.count)
}
}
When i'm pressing the button in my app, i can see the NFC reading window on my phone
iOS app NFC reading window
But, when i put the card up to a phone, there is noting happened. Android Studio console
Android studio console
2. NFCNDEFReaderSession
import UIKit
import Flutter
import CoreNFC
#available(iOS 13.0, *)
var session_tag: NFCNDEFReaderSession?
#available(iOS 13.0, *)
var flutterResult: FlutterResult!
#available(iOS 13.0, *)
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate, NFCNDEFReaderSessionDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let nfcChannel = FlutterMethodChannel(name: "samples.flutter.dev/nfc", binaryMessenger: controller.binaryMessenger)
nfcChannel.setMethodCallHandler({
[weak self] (call: FlutterMethodCall, result: #escaping FlutterResult) -> Void in
// Note: this method is invoked on the UI thread.
guard call.method == "getNFCTag" else {
result(FlutterMethodNotImplemented)
return
}
if NFCNDEFReaderSession.readingAvailable {
print("we are ready for reading");
self?.startReadingNFC(result: result)
} else {
print("sorry byt not working");
}
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func startReadingNFC(result: #escaping FlutterResult) {
print("start reading session")
flutterResult = result
// session_tag = NFCNDEFReaderSession(pollingOption: [.iso14443], delegate: self, queue: DispatchQueue.main)
session_tag = NFCNDEFReaderSession(delegate: self, queue: DispatchQueue.main, invalidateAfterFirstRead: false)
session_tag?.alertMessage = NSLocalizedString("Hold it!", comment: "my comment")
session_tag?.begin()
}
func tagReaderSessionDidBecomeActive(_ session: NFCNDEFReaderSession) {
print("Tag session active")
}
func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
print(messages)
for message in messages {
for record in message.records {
print("next message")
print(record)
}
}
}
func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) {
if (tags.count > 0) {
session.connect(to: tags.first!, completionHandler: { (connection_error) in
tags.first?.readNDEF(completionHandler: { (message, error) in
if ((message?.records.count)! > 0) {
if let dataMessage = String(data: (message?.records.first!.payload)!, encoding:.utf8) {
session.invalidate()
print(dataMessage)
}
}
})
})
}
}
func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
print("Tag Error: \(error.localizedDescription)")
}
func tagReaderSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
print("Tag Error: \(error.localizedDescription)")
// DispatchQueue.main.async {
// session.invalidate()
// print(error.localizedDescription)
// flutterResult(error.localizedDescription)
// }
}
}
After pressing the button in the app, NFC reading window also shows up. And with the card i can get the payload
Message: My message with spaces
Both approaches start fine and open the iOS's window with "read a tag", but with NFCTagReaderSession nothing is happening. It seems like there is no card. With NFCNDEFReaderSession implementation, I can read the message "My text with spaces" but, of course, I can't read the tag's UID
Am'I doing something wrong to get the UID of the card?
I want to implement platform specific code for my Flutter app on iOS. I want to implement EventKit from native iOS. but now I am confused how to implement protocol delegate pattern in the app delegate when using Platform Channel in Flutter.
in native iOS, my code will be like this
import EventKitUI
class MyViewController : UIViewController, EKEventEditViewDelegate, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func buttonPressed(_ sender: Any) {
// after pressing a button then show a VC
showEventKitViewController()
}
func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
// this is the method to conform the protocol
dismiss(animated: true, completion: nil)
}
func showEventKitViewController() {
let eventVC = EKEventEditViewController()
eventVC.editViewDelegate = self // I am confused in this line
eventVC.eventStore = EKEventStore()
let event = EKEvent(eventStore: eventVC.eventStore)
eventVC.event = event
present(eventVC, animated: true)
}
}
as you can see, I assign self ( MyViewController class as the delegate ) for editViewDelegate
now I am confused how to implement showEventKitViewController method above in Flutter app delegate below
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "useOtherApp", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({ (call: FlutterMethodCall, result: FlutterResult) -> Void in
if (call.method == "saveToEventKit") {
// what should I do in here to get the same result like my code above in native?
}
})
}
especially when I need to assign a class as the delegate for editViewDelegate like this
I can solve it by using the code like this by using extension. please scroll to the very bottom to see FlutterViewController extension
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
setUpMethodChannels(controller: controller) // set the method channel
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func setUpMethodChannels(controller: FlutterViewController) {
let channel = FlutterMethodChannel(name: "useOtherApp", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({ (call: FlutterMethodCall, result: FlutterResult) -> Void in
guard let args = call.arguments as? [String : Any] else {return}
if (call.method == "saveToCalendar") {
let eventVC = EKEventEditViewController()
eventVC.editViewDelegate = controller // set FlutterViewController as the delegate
eventVC.eventStore = EKEventStore()
let event = EKEvent(eventStore: eventVC.eventStore)
eventVC.event = event
eventVC.title = "hallooooo"
controller.present(eventVC, animated: true)
} else {
result(FlutterMethodNotImplemented)
}
})
}
}
// set the extension like below OUTSIDE the AppDelegate class
extension FlutterViewController : EKEventEditViewDelegate, UINavigationControllerDelegate {
// conform to the EKEventEditViewDelegate protocol
public func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
dismiss(animated: true, completion: nil)
}
}
I want to run the function in the background. But I get an error. The error I received is
"nw_connection_receive_internal_block_invoke.
Why am I getting this problem? I'm trying it on an iOS 13 device. But I can't run the application in the background. I added a background run feature in Info.plist. I want to run the interator.tickTimer function in the background. But I'm getting an error. Does not work in the background. In the background, I want to periodically retrieve data from firebase.
import BackgroundTasks
#available(iOS 13.0, *)
extension AppDelegate {
func cancelAllPandingBGTask() {
BGTaskScheduler.shared.cancelAllTaskRequests()
}
func scheduleImageFetcher() {
let request = BGProcessingTaskRequest(identifier: "....")
request.requiresNetworkConnectivity = true // Need to true if your task need to network process. Defaults to false.
request.requiresExternalPower = false
request.earliestBeginDate = Date(timeIntervalSinceNow: 40)
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule image featch: \(error)")
}
}
func handleAppRefreshTask(task: BGAppRefreshTask) {
task.expirationHandler = {
}
DispatchQueue.main.async {
let interator = MainTableViewController()
interator.tickTimer()
}
task.setTaskCompleted(success: true)
}
func handleImageFetcherTask(task: BGProcessingTask) {
scheduleImageFetcher() // Recall
//Todo Work
task.expirationHandler = {
}
task.setTaskCompleted(success: true)
}
}
xtension AppDelegate {
func registerLocalNotification() {
let notificationCenter = UNUserNotificationCenter.current()
let options: UNAuthorizationOptions = [.alert, .sound, .badge]
notificationCenter.requestAuthorization(options: options) {
(didAllow, error) in
if !didAllow {
// print("User has declined notifications")
}
}
}
func scheduleLocalNotification() {
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.getNotificationSettings { (settings) in
if settings.authorizationStatus == .authorized {
self.fireNotification()
}
}
}
func fireNotification() {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Bg"
notificationContent.body = "BG Notifications."
// Add Trigger
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 1.0, repeats: false)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "local_notification", content: notificationContent, trigger: notificationTrigger)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}
}
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 13.0, *) {
registerBackgroundTaks()
registerLocalNotification()
} else {
// Fallback on earlier versions
}
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
if #available(iOS 13.0, *) {
cancelAllPandingBGTask()
scheduleImageFetcher()
} else {
// Fallback on earlier versions
}
}
//MARK: Regiater BackGround Tasks
#available(iOS 13.0, *)
private func registerBackgroundTaks() {
BGTaskScheduler.shared.register(forTaskWithIdentifier: "....-...", using: nil) { task in
//This task is cast with processing request (BGProcessingTask)
self.scheduleLocalNotification()
self.handleImageFetcherTask(task: task as! BGProcessingTask)
}
}
I'm using Firebase Remote Config, I have some troubles to update values.
My values are updated only if I close and relaunch the app.
But never if my app enters in foreground.
The developer is activated, with no cache delay.
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
let _ = RCFirebaseValues.sharedInstance
}
}
My Firebase Remote Config class:
enum ValueKey: String {
case force_update
}
class RCFirebaseValues {
static let sharedInstance = RCFirebaseValues()
var loadingDoneCallback: (() -> ())?
var fetchComplete: Bool = false
private init() {
loadDefaultValues()
fetchCloudValues()
}
func loadDefaultValues() {
RemoteConfig.remoteConfig().setDefaults(fromPlist: "RemoteConfigDefaults")
}
func fetchCloudValues() {
#if DEBUG
let expirationDuration: TimeInterval = 0
RemoteConfig.remoteConfig().configSettings = RemoteConfigSettings(developerModeEnabled: true)
#else
let expirationDuration: TimeInterval = 3600
#endif
RemoteConfig.remoteConfig().fetch(withExpirationDuration: expirationDuration) {
[weak self] (status, error) in
guard error == nil else {
DLog(message:"Uh-oh. Got an error fetching remote values \(String(describing: error))")
return
}
RemoteConfig.remoteConfig().activateFetched()
self?.fetchComplete = true
self?.loadingDoneCallback?()
}
}
func bool(forKey key: ValueKey) -> Bool {
return RemoteConfig.remoteConfig()[key.rawValue].boolValue
}
func string(forKey key: ValueKey) -> String {
return RemoteConfig.remoteConfig()[key.rawValue].stringValue ?? ""
}
func double(forKey key: ValueKey) -> Double {
if let numberValue = RemoteConfig.remoteConfig()[key.rawValue].numberValue {
return numberValue.doubleValue
} else {
return 0.0
}
}
}
What's wrong?
EDIT after Mosbah's response:
class AppDelegate: UIResponder, UIApplicationDelegate {
var remoteConfig:RCFirebaseValues!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
self. remoteConfig = RCFirebaseValues.sharedInstance
}
}
Your RCFirebaseValues scope is wrong, it will be nil as soon as you are out of application: didFinishLaunchingWithOptions: so you should keep a strong reference to your object (create a var on AppDelegate).