There's a similar question that works on Objective-C, but I tried the same code in Swift and it never executes, neither in the main app, nor in the action extension.
My situation is similar to the one in the question above, that is, when running from the main app I want to use UIApplication.shared.open to open a link in Safari, but I want to ignore this part of the code on the App Extension.
The problem isn't finding out whether the app is running from an App Extension or not, but ignoring the code when building for the App Extension, so that the compiler does not give me the following error on build:
You could introduce a new Custom Flag (similar to the DEBUG flag) for the extension target. In your Build Settings look for the Custom Flags and add a new one (e.g. "EXTENSION"). Like here in the screenshot, but also do it for release.
In your Code you could then do something like
#if EXTENSION
// here goes code that is only compiled in the extension
#else
// here goes code that is only compiled outside the extension
#endif
Update: Please read the Apple provided documentation on App Extensions:
Some APIs Are Unavailable to App Extensions
Because of its focused role in the system, an app extension is ineligible to participate in certain activities. An app extension cannot:
Access a Application.shared object, and so cannot use any of the methods on that object
- Apple, App Extension Programming Guide
To programmatically find if the it the running extension via code it's really simple, just do this:
let bundleUrl: URL = Bundle.main.bundleURL
let bundlePathExtension: String = bundleUrl.pathExtension
let isAppex: Bool = bundlePathExtension == "appex"
// `true` when invoked inside the `Extension process`
// `false` when invoked inside the `Main process`
I just installed the first iOS 11 beta to an iPhone 7 and am interested in trying the NFC. There's nothing about it in settings. I am wondering if there's any sample code out there showing how to read a tag. Can anyone show how to use the Core NFC SDK, in a code snippet?
In the Apple Developer site, create a new App ID and make sure that NFC Tag Reading is enabled.
Add the following lines to your .plist file:
<key>NFCReaderUsageDescription</key>
<string>NFC Tag!</string>
and these to the entitlements file:
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
</array>
It should look something like this in the corresponding files:
Also Core NFC can be enabled via the Capabilities tab in Xcode.
Objective-c
Import CoreNFC
#import <CoreNFC/CoreNFC.h>
and set the delegate:
#interface YourViewController : UIViewController <NFCNDEFReaderSessionDelegate>
In viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NFCNDEFReaderSession *session = [[NFCNDEFReaderSession alloc] initWithDelegate:self queue:dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT) invalidateAfterFirstRead:NO];
[session beginSession];
}
In the delegate callback:
- (void) readerSession:(nonnull NFCNDEFReaderSession *)session didDetectNDEFs:(nonnull NSArray<NFCNDEFMessage *> *)messages {
for (NFCNDEFMessage *message in messages) {
for (NFCNDEFPayload *payload in message.records) {
NSLog(#"Payload data:%#",payload.payload);
}
}
}
You must also add the didInvalidateWithError delegate callback or you'll not conform with protocol:
- (void)readerSession:(nonnull NFCNDEFReaderSession *)session didInvalidateWithError:(nonnull NSError *)error {
}
You can stop the reader with:
[session invalidateSession];
Swift 3/4
Import CoreNFC
import CoreNFC
and set the delegate:
class YourViewController: UIViewController, NFCNDEFReaderSessionDelegate
In viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
let session = NFCNDEFReaderSession(delegate: self,
queue: DispatchQueue(label: "queueName", attributes: .concurrent), invalidateAfterFirstRead: false)
session?.begin()
}
In the delegate callback:
func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
for message in messages {
for record in message.records {
print(record.payload)
}
}
}
You can stop the reader with:
session.invalidateSession
Usage
After launching the view you should immediately see the iOS NFC reader dialog like so:
Once this dialog appears you have about a second to place the iPhone near the NFC tag you want to read. Otherwise, the field is deactivated (this seems to be a bug on Apple's end). I often needed to cancel and retry to get consistent readings. More details here.
To fix this issue you can add com.apple.developer.nfc.readersession.formats key into your entitlements file. The key should be associated with the array of enabled NFS types.
For instance, you can try the following:
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
</array>
It worked for me.
Updated for second Xcode beta.
Add the NFC capability to your app from the Developer Center. Identifiers -> App IDs -> enable "NFC Tag Reading".
If your project does not have an entitlement file, let Xcode create one for you by just activating and then subsequently deactivating any capability from within Xcode -> Project Targets -> Capabilities. You will find a new [AppName].entitlements file in your project navigator. Right-click on that file and select "Open as -> Source Code". Enter the following entry manually between <dict></dict>:
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
</array>
As soon as Xcode 9 allows enabling NFC Tag Reading from the Capabilities selection this step becomes obsolete because all you have to do is to enable it there. The current (first) Beta version does not support this.
You also need to enter a usage description for the privacy warning iOS will show the user. (At the moment (beta 1) this warning will be displayed when the device is ready to scan and shows a native system dialogue which will include this message. However, this seems to be unploished.) Open your target's Info.plist and start typing "Privacy" and you can scroll down to "Privacy - NFC Usage Description" to select it by hitting return. Enter a meaningful explanation to your user in the right column.
Now you should be able to import CoreNFC, in Swift:
import CoreNFC
Then head over to Apple's documentation.
Important: If the compiler returns an error with No such module 'CoreNFC' check if you have selected an actual iOS 11 device to build for, not a simulator. It also has to be the iPhone 7 or 7 plus. This might change in a future version, but testing NFC will only ever be fully working with actual hardware. (cp. Core Bluetooth where you can run on Simulator but not test the actual capabilities.) Beta 2 doesn't have this issue anymore. However, actual hardware in form of iPhone 7/p is still required for actual testing.
Just to enrich previous answers, it's important to bear in mind these considerations specifically of the NFCNDEFReaderSession class:
Reader session for processing NFC Data Exchange Format (NDEF) tags. This session requires the "com.apple.developer.nfc.readersession.formats" entitlement in your process. In addition your application's Info.plist must contain a non-empty usage description string.
A NDEF reader session will automatically scan and detect NFC Forum
tags that contain a valid NDEF message. NFC Forum Tag type 1 to 5
that is NDEF formatted are supported. A modal system UI will present
once -beginSession is called to inform the start of the session; the
UI sheet is automatically dismissed when the session is invalidated
either by the user or by calling -invalidateSession.
An opened session has a 60 seconds time limit restriction after -beginSession is called; -readerSession:didInvalidateWithError: will return NFCReaderSessionInvalidationErrorSessionTimeout error when the time limit is reached.
Only 1 active reader session is allowed in the system; -readerSession:didInvalidateWithError: will return NFCReaderSessionInvalidationErrorSystemIsBusy when a new reader session is initiated by -beginSession when there is an active reader session.
-readerSession:didInvalidateWithError: will return NFCReaderSessionInvalidationErrorUserCanceled when user clicks on the done button on the UI.
-readerSession:didInvalidateWithError: will return NFCReaderSessionInvalidationErrorSessionTerminatedUnexpectedly when the client application enters the background state.
-readerSession:didInvalidateWithError: will return NFCReaderErrorUnsupportedFeature when
reader mode feature is not available on the hardware
client application does not have the required entitlement.
You need to make sure the usage description is in place and also add the capability to the app inside of the Apple Developer Center.
I have a tutorial based on my experience (Swift 4-based). It's available here: Core NFC Tutorial
I added Core NFC to a project using the resources in these answers. One additional thing that wasn't noted though was that even if you add the capability manually via the entitlements, Xcode doesn't seem to look at the file unless you have a capability turned on. This is probably due to Xcode 9 Beta 1 not having Core NFC as a capability switch for lots of people's sample projects. So just be sure to turn at least one other capability on if you're still seeing issues! I was seeing an unexpected termination error immediately return until I did this.
I would leave this as a comment as it belongs, but don't have enough reputation yet to do so. Figured this was important enough to note.
my two cents:
1) under xcode 9.0 (beta 4 9M189t ) if You have already added capabilities,
no need to manually add:
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
</array>
it is done automatically
2) no crash if not using iPhone 7 OR you are in simulator:
You wil be called in:
func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
print(error.localizedDescription)
}
it will show:
"Feature not supported"
3) dont miss:
self.nfcSession?.begin() // will trigger callback
so:
final private func setup(){
self.nfcSession = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: true)
self.nfcSession?.alertMessage = "Put your NFC TAG over iPhone.."
self.nfcSession?.begin() // will trigger callback
}
4) if user cancels, you will get:
"Session is invalidated by user cancellation"
in didInvalidateWithError callback.
I have implemented siri extension to my app messages (siri kit iOS10) as shown in apple sample code
I implemented siri extension class to get number and message body from siri voice
this two parameters passing to my app source code
here Xcode showing linker command error
i didn't understand what i am missing in this code
When add this code to extension class it showing
error:[[UCSMSHandleManager sharedinstance] sendTextMessage:digits withMsg:message];
HI i'm trying to develop a function that uses APPLOVIN to show adds. i don't see any errors messages an nothing, The game starts normally but no add is shown
I imported the library
I think i'm doing all the correct steps:
1)Importing all libraries into the project
2)setting the KEY that APPLOVIN provides
3) set the -OgjC configuration key
4)Do all imports into the delegate class
5) load library
[ALSdk initializeSdk];
and
[ALInterstitialAd showOver:[[UIApplication sharedApplication] keyWindow]];
I did all the steps posted here: https://www.applovin.com/integration#iosIntegration
Is it any step that i need to perform in order to show an add?
I looked into some other posts and they use an banner object, but don't know how to integrate in COCOS2d. can someone provide some guidance on this please?
Thanks in Advance!!
Applovin Integration Steps :
Initialize
-(void)applicationDidBecomeActive:(UIApplication *)application
{
[ALSdk initializeSdk];
}
Show Ads :
-(void)showAplovinAds
{
[ALInterstitialAd showOver:[[UIApplication sharedApplication] keyWindow]];
}
Add SDK Key in info.plist
I'm getting the following error after a crash in an iPad app that uses CoreMIDI (The * are to blank out the app name):
Dyld Error Message:
Symbol not found: _MIDINetworkNotificationContactsDidChange
Referenced from:
/var/mobile/Applications/8F08B78E-929D-4C5A-9F02-08FD5743C17F/***.app/***
Expected in: /System/Library/Frameworks/CoreMIDI.framework/CoreMIDI
in /var/mobile/Applications/8F08B78E-929D-4C5A-9F02-08FD5743C17F/***.app/***
Dyld Version: 179.4
When the app launches, I listen for MIDI Network Sessions using
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(sessionDidChange:) name:MIDINetworkNotificationSessionDidChange object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(sessionDidChange:) name:MIDINetworkNotificationContactsDidChange object:nil];
Which seems to be what is causing the crash. This is after I call
session = [MIDINetworkSession defaultSession];
session.enabled = YES;
session.connectionPolicy = MIDINetworkConnectionPolicy_Anyone;
MIDIClientCreate(CFSTR("MidiManager"), midiNotifyProc, (void*)self, &midiClientRef);
This kind of looks like CoreMIDI library has not been included in the build. Problem is, it IS included in the build as a required framework. (And the deployment target is set to 4.2). I can run the build fine on my iPad and have been testing extensively with other users' iPads also with no problems whatsoever. Also, this is an update to an existing app that has had several updates already with no problems.
I just double checked my deployment build and the framework is definitely included, and I just installed that build onto my iPad (with a different provisioning profile from the store) and it works fine also.
What could be happening? Could it be that Xcode just did a bad build for the one I sent to Apple, or am I missing something obvious? Could I change the MIDINetworkNotificationSessionDidChange notification symbol to a literal string (#"MIDINetworkNotificationSessionDidChange") to fix things for the mean time?
Thanks for any help!
Seems like this was an Apple thing. The .mm of PGMidi's workhorse class includes this at the top:
// For some reason, this is not pulled in by the umbrella header
#import <CoreMIDI/MIDINetworkSession.h>
https://github.com/petegoodliffe/PGMidi
Did you remember to set the minimum OS requirements to 4.2 in your Info.plist? It could be that the crash reports are coming from users on an earlier version of iOS who are upgrading when they shouldn't be.