Swift-4 Siren, Update App dialog disappears immediately - swift

I use Siren library to check app version. It shows a dialog to notify there is an update, but after the webview is loaded dialog disappears so user is not able to click anything. How to prevent this?
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let gcmMessageIDKey = "gcm.message_id"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
Messaging.messaging().delegate = self
Siren.shared.wail { (results, error) in
if let results = results {
print("AlertAction ", results.alertAction)
print("Localization ", results.localization)
print("LookupModel ", results.lookupModel)
print("UpdateType ", results.updateType)
} else if let error = error {
print(error.localizedDescription)
}
}
}
...
class ViewController: UIViewController , WKUIDelegate , WKScriptMessageHandler, WKNavigationDelegate{
...........
var webView : WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
//let url = URL(string: "http://dev.smartiq.io/mars/mobile/index.html#main" )!
//let url = URL(string: "http://mars.visteknoloji.com/mars/mobile/index.html#main")!
let url = URL(string: "https://dev.smartiq.io/mars/mobile/index.html#main")!
//let url = URL(string: "http://192.168.3.22:8080/mars/mobile/index.html#main")!
webView.scrollView.bounces = false;
webView.load(URLRequest(url: url))
webView.navigationDelegate = self
.....
let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
let date = Date(timeIntervalSince1970: 0)
WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes as! Set<String>, modifiedSince: date, completionHandler:{ })
// Do any additional setup after loading the view, typically from a nib.
}
Here I load the wkwebview, when it shows update dialog disappears
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
let controller = WKUserContentController()
controller.add(self ,name : "JSListener")
webConfiguration.userContentController = controller
webView = WKWebView(frame: .zero, configuration: webConfiguration)
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.barTintColor = .gray
webView.uiDelegate = self
view = webView
}

Related

Firebase iOS clicking on shortened link returns ' Receive failed with error "Software caused connection abort" '

I'm just going to paste in a couple of my files so that you can test this really easily and see what's going on. I'm clicking the button and it's making the shortened dynamic link. Then, I'm typing out the DynamicLink in the notes app and then I press the link. I get redirected to the app and the following error is returned:
[connection] nw_read_request_report [C1] Receive failed with error "Software caused connection abort"
Side note: all of this is being tested on an iPhone 7 (a physical device, not the simulator).
FirebaseTestApp and AppDelegate:
import SwiftUI
import Firebase
#main
struct FirebaseTestApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
var functionMaster: functions = functions()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
return true
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url)
if dynamicLink != nil {
print("Dynamic link : \(String(describing: dynamicLink?.url))")
return true
}
return false
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
print("Successful penetration")
guard let inComingURL = userActivity.webpageURL else { return false }
print("Incoming Web Page URL: \(inComingURL)")
self.functionMaster.handleIncomingDynamicLink(inComingURL)
return true
}
}
functions class:
import Foundation
import Firebase
import UIKit
class functions: ObservableObject {
func makeDynamicLink() {
var components = URLComponents()
components.scheme = "https"
components.host = "www.firebase-test.com" //this can be some random domain right? It doesn't have to actually exist yet?
components.path = "/data"
let stringifiedNumber = String(123)
components.queryItems = [stringifiedNumber]
let dynamicLinksDomainURIPrefix = "https://something.page.link"
guard let linkParameter = components.url else { return }
print("I am sharing \(linkParameter)")
guard let linkBuilder = DynamicLinkComponents(link: linkParameter, domainURIPrefix: dynamicLinksDomainURIPrefix) else { return }
if let myBundleId = Bundle.main.bundleIdentifier {
linkBuilder.iOSParameters = DynamicLinkIOSParameters(bundleID: myBundleId)
}
linkBuilder.iOSParameters?.appStoreID = "962194608"
linkBuilder.socialMetaTagParameters = DynamicLinkSocialMetaTagParameters()
linkBuilder.socialMetaTagParameters?.title = testLocation.name
linkBuilder.socialMetaTagParameters?.descriptionText = testLocation.address
linkBuilder.shorten { [weak self] (url, warnings, error) in
if let error = error{
print("Firebase encountered an error: \(error)")
return
}
if let warnings = warnings {
for warning in warnings {
print("Firebase Warning: \(warning)")
}
}
guard let url = url else { return }
print("The short URL is: \(url.absoluteString)")
self?.showShareSheet(url: url)
}
guard let longDynamicLink = linkBuilder.url else { return }
print("The long URL is: \(longDynamicLink)")
}
func showShareSheet(url: URL) {
let promoText = "Check out this thing I've marked in FirebaseTest!"
let activityVC = UIActivityViewController(activityItems: [promoText, url], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(activityVC, animated: true)
}
func handleIncomingDynamicLink(_ dynamicLink: URL) {
_ = DynamicLinks.dynamicLinks().handleUniversalLink(dynamicLink) { (dynamiclink, error) in
guard error == nil else {
print("Found an error: \(error?.localizedDescription ?? "")")
return
}
print("Dynamic link : \(String(describing: dynamiclink?.url))")
let path = dynamiclink?.url?.path
var id = 0
if let query = dynamiclink?.url?.query {
let dataArray = query.components(separatedBy: "=")
id = Int(dataArray[1]) ?? 0
}
if path == "data" {
//Write code here
}
}
}
}
ContentView:
import SwiftUI
struct ContentView: View {
#ObservedObject var functionMaster: functions = functions()
var body: some View {
Button("Click me to run some firebase stuff") {
functionMaster.makeDynamicLink()
}
.padding()
}
}
In browser, when I navigate to https://something.page.link/apple-app-site-association, I get this:
https://i.stack.imgur.com/6Ndo0.png
Try installing the files for the the simulator you want to test on, update Xcode, delete all other versions.

How to uiview into a CPtemplate

I'm trying to replace the map on the carplay app of this sample project by a carplay webview.
Here the function that returns the root template, to be show on CarPlay :
The problem, is that the setRootTemplate function needs a CPTemplate, and I don't know how to create a template and put a uiview on that ?
func application(_ application: UIApplication, didConnectCarInterfaceController interfaceController: CPInterfaceController, to window: CPWindow) {
let webViewClass : AnyObject.Type = NSClassFromString("UIWebView")!
let webViewObject : NSObject.Type = webViewClass as! NSObject.Type
let webview: AnyObject = webViewObject.init()
let url = NSURL(string: "https://www.google.com")
let request = NSURLRequest(url: url! as URL)
webview.loadRequest(request as URLRequest)
let uiview = webview as! UIView
// tried that too... let myCPTemplateHere = webview as! CPTemplate
// Here
interfaceController.setRootTemplate(myCPTemplateHere, animated: true)
}
I tried with WKWebView too
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
let myURL = URL(string:"https://www.apple.com")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
Thanks a lot !
PS: This app is for my own usage, I will not send it to the app store.

MPRemoteCommandCenter doesn't appear on iOS13

I have a video player that show a .m3u8 stream. I've tried to implement the Remote Control but the widget doesn't appear both in lock screen, in the Notification Center and in the Command Center.
I need only to have play-pause, volume controls and some static info as Title, Artist and Artwork.
This is my code:
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print(error.localizedDescription)
}
return true
}
ViewController.swift
class ViewController: UIViewController {
var player = AVPlayer()
var playerViewcontroller = AVPlayerViewController()
var playerItem: AVPlayerItem!
var playerLayer = AVPlayerLayer()
#IBAction func playVideo(_ sender: Any) {
guard let url = URL(string: "https://video.m3u8") else {
return
}
// Create an AVPlayer, passing it the HTTP Live Streaming URL.
playerItem = AVPlayerItem(url: url)
playerItem.preferredForwardBufferDuration = 8
player = AVPlayer(playerItem: playerItem)
// Create a new AVPlayerViewController and pass it a reference to the player.
playerViewcontroller.player = player
playerViewcontroller.showsPlaybackControls = true
// Modally present the player and call the player's play() method when complete.
present(playerViewcontroller, animated: true) {
self.player.play()
}
setupNowPlaying()
}
override func viewDidLoad() {
//super.viewDidLoad()
}
public func disconnectAVPlayer() {
playerViewcontroller.player = nil
}
public func reconnectAVPlayer() {
playerViewcontroller.player = player
}
func setupNowPlaying() {
print("_________________________________setupPlaying")
// Define Now Playing Info
let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
var nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]()
let title = "TV NAME"
let album = "TV DESCRIPTION"
let image = UIImage(named: "ICON") ?? UIImage()
let artwork = MPMediaItemArtwork(boundsSize: image.size, requestHandler: { (_) -> UIImage in
return image
})
nowPlayingInfo[MPMediaItemPropertyTitle] = title
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = album
nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = NSNumber(value: 1.0)
nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
}
}
Hope that infos are sufficient. Thanks
Remote Control Works fine in iOS 13 , you just didn’t set it up first. Add this code after assigning to your AVPlayer
func commandCenterSetup() {
UIApplication.shared.beginReceivingRemoteControlEvents()
let commandCenter = MPRemoteCommandCenter.shared()
setupNowPlaying()
commandCenter.pauseCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
print("PAUSE")
self.playerViewcontroller.player.pause()
return .success
}
commandCenter.playCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
print("PLAY")
playerViewcontroller.player.play()
return .success
}
}

crash while try store value using dependency inversion

I want to implemented dependency inversion In app delegate in my app as my rootController is my UITabBarController but when I want to try it there is an error
Fatal error: Unexpectedly found nil while unwrapping optional value
This is my code in my appDelagate
let exploreStore = ExploreStore()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let rootController = (window?.rootViewController as? UITabBarController)?.children.first as? ExploreViewController
// Inject Data
rootController?.exploreStore = exploreStore
return true
}
This is my explore class
class ExploreStore {
fileprivate var allItems = [ExploreItem]()
func fetch() {
for data in loadData() {
allItems.append(ExploreItem(dict: data))
}
}
func numberOfItem() -> Int {
return allItems.count
}
func explore(at index: IndexPath) -> ExploreItem {
return allItems[index.item]
}
fileprivate func loadData() -> [[String: AnyObject]] {
guard
let path = Bundle.main.path(forResource: "ExploreData", ofType: "plist"),
let items = NSArray(contentsOfFile: path)
else { return [[:]] }
return items as! [[String: AnyObject]]
}
}
This is my exlporeViewController
var exploreStore: ExploreStore!
override func viewDidLoad() {
super.viewDidLoad()
// This is where the error found nil
exploreStore.fetch()
}
Actually the code work if I don't use dependency inversion, like my explore view controller not use force unwrapping like this
var exploreStore = ExploreStore()
but since I want gain knowledge and learn S.O.L.I.D principle using dependency inversion, I want to stick with this principle.
If I understood your question correctly you want to initialise your class at AppDelegate class and then you want to pass it to your UITabBarController's first children and for that you need to make some modifications into your didFinishLaunchingWithOptions method like shown below:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let vc = storyBoard.instantiateViewController(withIdentifier: "tabBar")
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = vc
let myTabBar = self.window?.rootViewController as! UITabBarController
let firstViewController = myTabBar.children.first as? FirstViewController
firstViewController?.exploreStore = exploreStore
self.window?.makeKeyAndVisible()
return true
}
Here I have made some modification's because I am retrieving Info.plist from Bundle and your ExploreStore will look like:
class ExploreStore {
var allItems = [ExploreItem]()
func fetch() {
if let dataObjectFromPlist = loadData() {
allItems.append(ExploreItem(dict: dataObjectFromPlist))
}
}
func numberOfItem() -> Int {
return allItems.count
}
func explore(at index: IndexPath) -> ExploreItem {
return allItems[index.item]
}
fileprivate func loadData() -> [String: AnyObject]? {
var resourceFileDictionary: [String: AnyObject]?
if let path = Bundle.main.path(forResource: "Info", ofType: "plist") {
if let dict = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
resourceFileDictionary = dict
}
}
return resourceFileDictionary
}
}
Then in my FirstViewController I can fetch the data from ExploreStore class with
exploreStore.fetch()
and my code for that UIViewController is
class FirstViewController: UIViewController {
var exploreStore: ExploreStore!
override func viewDidLoad() {
super.viewDidLoad()
exploreStore.fetch()
print(exploreStore.allItems[0].data)
}
}
Here exploreStore.allItems[0].data will print my whole info.plist file.
You can try it by your self with THIS demo project and check if that's the correct behaviour.
EDIT
You need to update didFinishLaunchingWithOptions method like:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
setupDefaultColors()
let exploreStoryBoard = UIStoryboard(name: "Explore", bundle:nil)
let navigationController = exploreStoryBoard.instantiateViewController(withIdentifier: "ExploreViewControllerNavigation") as! UINavigationController
if let exploreViewController = navigationController.children.first as? ExploreViewController {
exploreViewController.store = ExploreStore()
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = exploreViewController
self.window?.makeKeyAndVisible()
}
return true
}
And you also need to update ExploreStore class as shown below:
class ExploreStore {
var allItems = [ExploreItem]()
func fetch() {
if let dataObjectFromPlist = loadData() {
allItems.append(ExploreItem(dict: dataObjectFromPlist))
}
}
func numberOfItem() -> Int {
return allItems.count
}
func explore(at index: IndexPath) -> ExploreItem {
return allItems[index.item]
}
fileprivate func loadData() -> [String: AnyObject]? {
var resourceFileDictionary: [String: AnyObject]?
if let path = Bundle.main.path(forResource: "ExploreData", ofType: "plist") {
if let dict = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
resourceFileDictionary = dict
}
}
return resourceFileDictionary
}
}
Because from plist you will get Dictionary<String, AnyObject> type object.
And you will still not get data from plist file because its added into subfolder. So you need find correct path first for your plist.
You also needs to assign respective identifiers to navigation controller and tab bar controller.
Here is your demo project.

swift 3 facebook integration

trying to get Facebook connect working from a swift project.
Have been trying to follow along the following youtube video: https://www.youtube.com/watch?v=I6rTmfLp9aY
which unfortunately for me is in German.
so this is what I have so far:
I have my Facebook app with IOS enabled enabled and I planted my bundleID there.
Downloaded latest iOS framework and added to project
to the AppDelegate file I added:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FBSDKApplicationDelegate.sharedInstance()
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
FBSDKAppEvents.activateApp()
}
and this is the ViewController file
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
import FBSDKShareKit
class ViewController: UIViewController, FBSDKAppInviteDialogDelegate, FBSDKLoginButtonDelegate{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if (FBSDKAccessToken.current() != nil)
{
let content = FBSDKAppInviteContent()
content.appLinkURL = NSURL(string: "{Facebook link to app}") as URL!
FBSDKAppInviteDialog.show(from: self, with: content, delegate: self)
}
else
{
let loginView : FBSDKLoginButton = FBSDKLoginButton()
self.view.addSubview(loginView)
loginView.center = CGPoint(x: self.view.frame.midX, y: self.view.frame.midY + 100)
loginView.readPermissions = ["public_profile", "email"]
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func appInviteDialog (_ appInviteDialog: FBSDKAppInviteDialog!, didCompleteWithResults results: [AnyHashable : Any]!)
{
}
func appInviteDialog (_ appInviteDialog: FBSDKAppInviteDialog!, didFailWithError error: Error!) {
print("Error took place in appInviteDialog \(error)")
}
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if ((error) != nil)
{
//process error
}
else if result.isCancelled {
//handle cancelation
}
else {
let content = FBSDKAppInviteContent()
content.appLinkURL = NSURL(string: "{Facebook link to app}") as URL!
FBSDKAppInviteDialog.show(from: self, with: content, delegate: self)
if result.grantedPermissions.contains("email")
{
//do work
}
}
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
}
}
No errors and no alerts. When i run simulator I get an empty screen. Must be doing something right cause I get the following msg:
SystemGroup/systemgroup.com.apple.configurationprofiles
2017-06-04 00:42:02.351876+0300 facebook_login[4569:144075] [MC] Reading from private effective user settings.
also, if I just paste in viewDidLoad the following lines from the code:
let loginView : FBSDKLoginButton = FBSDKLoginButton()
self.view.addSubview(loginView)
loginView.center = CGPoint(x: self.view.frame.midX, y: self.view.frame.midY + 100)
loginView.readPermissions = ["public_profile", "email"]
I get a beautiful Facebook button in simulator that of course crashes when i press it.
any help to work will be greatly appreciated
Facebook has a Swift SDK you might find easier to use than the Objective-C one (which they just call iOS). Try looking around the documentation here:
https://developers.facebook.com/docs/swift
Also, follow the steps described in the (other) iOS SDK to get started:
https://developers.facebook.com/docs/ios/getting-started/
This is the minimal app delegate I could get to work (notice the Swift SDK is missing the FB prefixes that exist in the iOS SDK):
import UIKit
import FacebookCore
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
SDKApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return SDKApplicationDelegate.shared.application(app, open: url, options: options)
}
}
And be sure to add all the required keys in your Info.plist or else you won't get authentication to work at all.
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith
result:FBSDKLoginManagerLoginResult!, error: Error!) {
if ((error) != nil) {
// Process error
print("Error! : \(error.localizedDescription)")
return
} else if result.isCancelled {
// Handle cancellations
print("Success! : user cancel login request")
return
} else {
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields" : "id, email, name,picture.type(large)"])
graphRequest.start(completionHandler: { (connection, result, error) -> Void in
if ((error) != nil) {
print("Error: \(error)")
} else {
// Do work in app.
let dataDict:NSDictionary = result as! NSDictionary
if let token = FBSDKAccessToken.current().tokenString {
print("tocken: \(token)")
let userDefult = UserDefaults.standard
userDefult.setValue(token, forKey: "access_tocken")
userDefult.synchronize()
}
if let user : NSString = dataDict.object(forKey: "name") as! NSString? {
print("user: \(user)")
}
if let id : NSString = dataDict.object(forKey: "id") as? NSString {
print("id: \(id)")
}
if let email : NSString = (result! as AnyObject).value(forKey: "email") as? NSString {
print("email: \(email)")
}
if let pictureData:NSDictionary = dataDict.object(forKey: "picture") as? NSDictionary{
if let data:NSDictionary = pictureData.object(forKey: "data") as? NSDictionary{
if let strPictureURL: String = data.object(forKey: "url") as? String{
self.imageviewUser.image = UIImage(data: NSData(contentsOf: NSURL(string: strPictureURL)! as URL)! as Data)
}
}
}
}
})
}
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!)
{
FBSDKAccessToken.setCurrent(nil)
FBSDKProfile.setCurrent(nil)
let manager = FBSDKLoginManager()
manager.logOut()
}