import UIKit
import CoreNFC
class ViewController: UIViewController, NFCTagReaderSessionDelegate {
var nfcTagReaderSession: NFCTagReaderSession?
func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
print("Tag reader did become active")
print("isReady: \(nfcTagReaderSession?.isReady)")
}
func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
print("\(error)")
}
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
// this part is never called!
print("got a Tag!")
print("\(tags)")
}
#IBAction func clickedNFC(_ sender: Any) {
nfcTagReaderSession = NFCTagReaderSession(pollingOption: [.iso14443], delegate: self)
nfcTagReaderSession?.alertMessage = "Place the device on the innercover of the passport"
nfcTagReaderSession?.begin()
print("isReady: \(nfcTagReaderSession?.isReady)")
}
}
I also have in my entitlements file
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
<string>TAG</string>
</array>
and in my Info.plist
<key>NFCReaderUsageDescription</key>
<string>Read the NFC chip of ePassports</string>
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>A0000002471001</string>
</array>
My problem is that tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) is never being called. What am I missing?
I found the solution I added 00000000000000 to the com.apple.developer.nfc.readersession.iso7816.select-identifiers entry in the Info.plist
Now it looks like this:
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>A0000002471001</string>
<string>00000000000000</string>
</array>
Related
Please excuse me if I sound stupid, I'm new to flutter.
I have started learning flutter recently and wanted to create an app where anyone can share a contact from the "Recent" calls list to my app. I'm following this blog post which allows text share from any other app to my app.
What I have done so far:
This is my plist file, added the public.vcard to allow my app to appear on the tap of "Share Contact".
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<string>
SUBQUERY (
extensionItems, $extensionItem,
SUBQUERY (
$extensionItem.attachments, $attachment,
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.vcard"
).#count >= 1
).#count > 0
</string>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
</dict>
</plist>
Here's my ShareViewController.swift
import Social
import MobileCoreServices
class ShareViewController: SLComposeServiceViewController {
override func isContentValid() -> Bool {
// Do validation of contentText and/or NSExtensionContext attachments here
print("Something is not right")
return true
}
override func didSelectPost() {
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
let sharedSuiteName: String = "group.com.thelogicalbeing.whatsappshare"
let sharedDataKey: String = "SharedData"
let extensionItem = extensionContext?.inputItems[0] as! NSExtensionItem
let contentTypeText = kUTTypeText as String // Note, you need to import 'MobileCoreServices' for this
for attachment in extensionItem.attachments! {
print(attachment)
if attachment.hasItemConformingToTypeIdentifier(contentTypeText) {
attachment.loadItem(forTypeIdentifier: contentTypeText, options: nil, completionHandler: {(results, error) in
if let sharedText = results as! String? {
if let userDefaults = UserDefaults(suiteName: sharedSuiteName) {
userDefaults.set(sharedText, forKey: sharedDataKey)
}
}
})
}
}
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
override func configurationItems() -> [Any]! {
// To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
return []
}
}
Here's my AppDelegate.swift
import UIKit
import Flutter
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
let sharedSuiteName: String = "group.com.thelogicalbeing.whatsappshare"
let sharedDataKey: String = "SharedData"
let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
let methodChannel = FlutterMethodChannel(name: "com.thelogicalbeing.whatsappshare", binaryMessenger: controller.binaryMessenger)
methodChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: #escaping FlutterResult) -> Void in
if call.method == "getSharedData" {
if let prefs = UserDefaults(suiteName: sharedSuiteName) {
if let sharedText = prefs.string(forKey: sharedDataKey) {
result(sharedText);
}
// clear out the cached data
prefs.set("", forKey: sharedDataKey);
}
}
})
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
What I'm trying to achieve is that I need to receive the phone number and display it in my app.
Don't know how to proceed. Any help will be appreciated.
1- Apple does not allow fetching call logs on iOS!
You can fetch all contacts with all their information. But not the calls log.
2- On Android you can use the pub.dev dependency plugin call_log to do that.
Have a look at this package called receive_sharing_intent, it allows you to to receive sharing photos, videos, text, urls or any other file types from another app. And it also supports iOS Share extension and launching the host app automatically.
I am trying to get some data off a server that created I using asp.net core, however; when trying to get the data in my Swift iOS code it keeps on failing without any error showing. I have done all the TSL checks in my info.plist.
model.swift
import Foundation
struct User: Decodable {
let name:String
let userEmail: String
let firebaseId: String
let userMode: Int
let profileImg: String
let loginType: Int?
}
userController.swift
import UIKit
import ProgressHUD
class LoginViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
removeNavBar()
// UserApiService.shared.makeGetAPICall(user:{users, error in
// // ProgressHUD.dismiss()
// guard let users = users else {return}
// print(users)
// guard let errors = error else {return}
// print(errors)
// })
}
#IBAction func googleLogin(_ sender: Any) {
ProgressHUD.animationType = .circleSpinFade
ProgressHUD.show()
UserApiService.init().makeGetAPICall(user: {users, error in
ProgressHUD.dismiss()
guard let users = users else {return}
print(users)
guard let errors = error else {return}
print(errors)
})
}
private func removeNavBar(){
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
apiService.swift
import Foundation
import Alamofire
class UserApiService{
static let shared = UserApiService.init()
let session: Session = {
let manager = ServerTrustManager(allHostsMustBeEvaluated: false,evaluators: ["localhost:5001": DisabledTrustEvaluator()])
let configuration = URLSessionConfiguration.af.default
return Session(configuration: configuration, serverTrustManager: manager)
}()
//MARK:- GET
func makeGetAPICall(user completionHandler: #escaping ([User]?,Error?) -> Void) {
var urlComponent = URLComponents()
urlComponent.scheme = "https"
urlComponent.host = "localhost"
urlComponent.port = 5001
urlComponent.path = "/api/user"
print(urlComponent.url!)
guard let url = urlComponent.url else {
return
}
session.request(url, method: .get).validate().responseDecodable(of: [User].self) {(response) in
switch response.result{
case .success:
guard let users = response.value else {
return
}
print(users)
completionHandler(users, nil)
case .failure(let error):
completionHandler(nil, error)
}
}
}
}
info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
<key>NSAllowsArbitraryLoadsForMedia</key>
<true/>
<key>NSAllowsLocalNetworking</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
I debugged it with breakpoints, and I am getting <unavailable; try printing with "VO" or "PO">. I'm having trouble understanding what that means and how I should resolve this.
Also, I have changed my info.plist and it looks like this, however; I am still getting the same issue
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoadsForMedia</key>
<true/>
<key>NSAllowsLocalNetworking</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
So I managed to fix my issue, Hooray!!!
What I did was, I changed evaluators: ["localhost:5001": DisabledTrustEvaluator() to evaluators: ["localhost": DisabledTrustEvaluator()
Also, when calling my method, I was referencing normally from a class but then after, I had to call it as a singleton, and then, HEY PRESTO, IT WORKED!
#IBAction func googleLogin(_ sender: Any) {
ProgressHUD.animationType = .circleSpinFade
ProgressHUD.show()
UserApiService.shared.makeGetAPICall(user: {users, error in
ProgressHUD.dismiss()
guard let users = users else {return}
print(users)
guard let errors = error else {return}
print(errors)
})
}
This link helped me figure out part of the reason for my issues https://github.com/Alamofire/Alamofire/issues/3336
In the following code I can read text in this way and print the text in the code.
But I do not know how to share txt file as an attachment and read it out in the following code.
import UIKit
import Social
import CoreServices
class ShareViewController: SLComposeServiceViewController {
private var textString: String?
override func isContentValid() -> Bool {
// Do validation of contentText and/or NSExtensionContext attachments here
if textString != nil {
if !contentText.isEmpty {
return true
}
}
return true
}
override func viewDidLoad() {
super.viewDidLoad()
let extensionItem = extensionContext?.inputItems[0] as! NSExtensionItem
let contentTypeText = kUTTypeText as String
for attachment in extensionItem.attachments! {
if attachment.isText {
attachment.loadItem(forTypeIdentifier: contentTypeText, options: nil, completionHandler: { (results, error) in
let text = results as! String
self.textString = text
_ = self.isContentValid()
})
}
}
}
override func didSelectPost() {
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
print(String(textString!)) // <-- I cannot read txt file and print it
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
override func configurationItems() -> [Any]! {
// To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
return []
}
}
//MARK: NSItemProvider check
extension NSItemProvider {
var isText: Bool {
return hasItemConformingToTypeIdentifier(kUTTypeText as String)
}
}
Is there any method to share the txt file as an attachment in Share Extension?
Thanks for any help.
First of all, in info.plist of your share extension you have to set what type of attachments and how many your extension can get
Example:
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>10</integer>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
All keys you can find here
When your extension recives attachment first you need to check it for type(is it what you are expecting to recive).
And then, in didSelectPost() you can get that attachment and do something with it (maybe store it in your app if that's what you want).
Here is nice article about shere extension for photos
How can I get a URL from webView whenever the URL is changed?
I want to change the button color when current URL is changed. So I need to check the current URL all the time.
And I also would like to get URL value as a String.
I tried the below code but it doesn't work at all.
NotificationCenter.default.addObserver(self, selector: #selector(urlChecker), name: NSNotification.Name.NSURLCredentialStorageChanged, object: webView)
you can use:
1. Solution
UIWebViewDelegate
https://developer.apple.com/reference/uikit/uiwebviewdelegate/1617945-webview
optional func webView(_ webView: UIWebView,
shouldStartLoadWith request: URLRequest,
navigationType: UIWebViewNavigationType) -> Bool
UIWebViewNavigationType:
https://developer.apple.com/reference/uikit/uiwebviewnavigationtype
don't forget to return true
case linkClicked
User tapped a link.
case formSubmitted
User submitted a form.
case backForward
User tapped the back or forward button.
case reload
User tapped the reload button.
case formResubmitted
User resubmitted a form.
case other
Some other action occurred.
2. Solution
Inject Javascript JavaScript MessageHandler
(credit to Vasily Bodnarchuk)
Solution is here: https://stackoverflow.com/a/40730365/1930509
Swift 3 example.
Description
The script is inserted into page which will displayed in WKWebView.
This script will return the page URL (but you can write another
JavaScript code). This means that the script event is generated on the
web page, but it will be handled in our function:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {...}
Full Code example
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
var webView = WKWebView()
let getUrlAtDocumentStartScript = "GetUrlAtDocumentStart"
let getUrlAtDocumentEndScript = "GetUrlAtDocumentEnd"
override func viewDidLoad() {
super.viewDidLoad()
let config = WKWebViewConfiguration()
config.addScript(script: WKUserScript.getUrlScript(scriptName: getUrlAtDocumentStartScript),
scriptHandlerName:getUrlAtDocumentStartScript, scriptMessageHandler:
self, injectionTime: .atDocumentStart)
config.addScript(script: WKUserScript.getUrlScript(scriptName: getUrlAtDocumentEndScript),
scriptHandlerName:getUrlAtDocumentEndScript, scriptMessageHandler:
self, injectionTime: .atDocumentEnd)
webView = WKWebView(frame: UIScreen.main.bounds, configuration: config)
webView.navigationDelegate = self
view.addSubview(webView)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
webView.loadUrl(string: "http://apple.com")
}
}
extension ViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
switch message.name {
case getUrlAtDocumentStartScript:
print("start: \(message.body)")
case getUrlAtDocumentEndScript:
print("end: \(message.body)")
default:
break;
}
}
}
extension WKUserScript {
class func getUrlScript(scriptName: String) -> String {
return "webkit.messageHandlers.\(scriptName).postMessage(document.URL)"
}
}
extension WKWebView {
func loadUrl(string: String) {
if let url = URL(string: string) {
load(URLRequest(url: url))
}
}
}
extension WKWebViewConfiguration {
func addScript(script: String, scriptHandlerName:String, scriptMessageHandler: WKScriptMessageHandler,injectionTime:WKUserScriptInjectionTime) {
let userScript = WKUserScript(source: script, injectionTime: injectionTime, forMainFrameOnly: false)
userContentController.addUserScript(userScript)
userContentController.add(scriptMessageHandler, name: scriptHandlerName)
}
}
Info.plist
add in your Info.plist transport security setting
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Result
Resources ##
Document Object Properties and Methods
I followed this tutorial https://www.youtube.com/watch?v=cpANieebE2M, But I used CocoaPod to install FBSDK, not download framework and drag to my project.
I used FBSDK Version: 4.10.1
Here is my pod file:
# Uncomment this line to define a global platform for your project
platform :ios, '8.0'
# Uncomment this line if you're using Swift
use_frameworks!
target 'GiftsToMyFriends' do
pod "FBSDKCoreKit"
pod "FBSDKLoginKit"
pod "FBSDKShareKit"
pod "FBSDKMessengerShareKit"
end
Here is my LoginViewController:
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
import FBSDKShareKit
import FBSDKMessengerShareKit
class LoginViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if (FBSDKAccessToken.currentAccessToken() == nil) {
print("Not loged in..")
} else {
print("Loged in...")
}
let loginButton = FBSDKLoginButton()
loginButton.readPermissions = ["public_profile", "email", "user_friends"]
loginButton.center = self.view.center
loginButton.delegate = self
self.view.addSubview(loginButton)
}
}
extension LoginViewController: FBSDKLoginButtonDelegate {
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
if error == nil {
print("login completed...")
self.performSegueWithIdentifier("goTo", sender: self)
} else {
print(error.localizedDescription)
}
}
func loginButtonDidLogOut(loginButton: FBSDKLoginButton!) {
print("User Loged out...")
}
}
But when I click to login button here:
It goes crash:
According to your screenshot, fbauth2 is missing from your info.plist file. You need to add this to your info.plist
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fbapi20130214</string>
<string>fbapi20130410</string>
<string>fbapi20130702</string>
<string>fbapi20131010</string>
<string>fbapi20131219</string>
<string>fbapi20140410</string>
<string>fbapi20140116</string>
<string>fbapi20150313</string>
<string>fbapi20150629</string>
<string>fbauth</string>
<string>fbauth2</string>
<string>fb-messenger-api20140430</string>
</array>
https://developers.facebook.com/docs/ios/ios9
As you didn't mention any specific version in the cocoa pods and if you have just integrated cocoa pods than you have to include only as you have higher SDK version than 4.6.0
If you're using v4.6.0 or higher of the SDK, you only need to add:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
If you version is still lower than 4.6.0 you can check Ahmed's answer
Also please check the if you have set the facebook app id in the plist if you still get the error after adding the LSApplicationQueriesSchemas
More information regarding that can be found in Getting Started : Facebook ios SDK
Check 5. Configure Xcode Project