I've got a problem with my inter-app communication on iPad which (up to recently) has been working. I'm using standard pasteboard code as found in http://enharmonichq.com/sharing-data-locally-between-ios-apps/ which is an excellent tutorial and works well.
My problem is that now my 'viewer' app is not receiving the pasteboard when it opens.
The code:
+(void)handleSendPasteboardDataURL:(NSURL *)sendPasteboardDataURL
completionHandler:(ENHAppDataSharingHandler)completionHandler;
{
NSString *query = [sendPasteboardDataURL query];
NSString *pasteboardName = [sendPasteboardDataURL fragment];
NSAssert2(([query isEqualToString:kReadPasteboardDataQuery] && pasteboardName),
#"Malformed or incorrect url sent to %#. URL: %#",
NSStringFromSelector(_cmd), sendPasteboardDataURL);
AppDataPackage *dataPackage = nil;
NSError *error = nil;
NSString *pasteboardType = kAppDataPackageUTI;
UIPasteboard *pasteboard = [UIPasteboard pasteboardWithName:pasteboardName create:NO];
if (pasteboard)
{
NSData *data = [pasteboard dataForPasteboardType:pasteboardType];
if (data)
{
dataPackage = [AppDataPackage unarchivePackageData:data];
}
else
{
NSDictionary *errorInfoDictionary = #{NSLocalizedDescriptionKey: [NSString stringWithFormat:
#"%# %#", NSLocalizedString(#"No data found on pasteboard with name:", nil),
pasteboardName]};
error = [NSError errorWithDomain:AppDataSharingErrorDomain
code:ENHAppDataSharingErrorTypeNoDataFound
userInfo:errorInfoDictionary];
}
[pasteboard setData:nil forPasteboardType:pasteboardType];
[pasteboard setPersistent:NO];
}
else
{
NSDictionary *errorInfoDictionary = #{NSLocalizedDescriptionKey:
[NSString stringWithFormat:#"%# %#",
NSLocalizedString(#"No pasteboard found for name:", nil), pasteboardName]};
error = [NSError errorWithDomain:AppDataSharingErrorDomain
code:ENHAppDataSharingErrorTypeNoPasteboardForName
userInfo:errorInfoDictionary];
}
completionHandler(dataPackage, error);
}
This has worked well previously on the device and still works well on the simulator. But now when tested on the device, the call...
[UIPasteboard pasteboardWithName:pasteboardName create:NO];
...fails and the pasteboard is nil. (pasteboard names are valid)
As I said this works OK on the simulator but not on the device.
So my question is if anyone else has had experience with the same problem?
Any suggestions as to what it could be?
My source app is working as other pasteboard 'test' apps can receive the data and work on the device. It's just my main receiving app is failing to get the pasteboard in question.
I'm a bit at my whit's end with this one.
This is running iOS7.1.2 and developing on xcode 5.1.1
Thanks
Related
I'm using Callkit extension to identify the numbers. All my contacts (around 30k+) are stored in Realm.
I have stored the Realm file in AppGroup which can be shared between my app and its extensions.
I get the error when I try to reload the extension.
Error Domain=com.apple.CallKit.error.calldirectorymanager Code=7
"(null)"
When this error occurred , the setting for Call Blocking & Identification for my app shows a spinner (while other apps show the switch to toggle)
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[CXCallDirectoryManager sharedInstance] reloadExtensionWithIdentifier:#"com.j2x.handheldcontact.CallerID" completionHandler:^(NSError *error){
if(error) {
NSLog(#"CallerID - refresh failed. error is %#",[error description]);
}
}];
}
I see that the error happens only when I try to use access the Realm in the app group directory.
In my extension subclass:
- (void)beginRequestWithExtensionContext:(CXCallDirectoryExtensionContext *)context
{
context.delegate = self;
NSString *appGroupId = #"group.com.j2x.handheldcontact.CallerID";
NSURL *appGroupDirectoryPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId];
NSURL *dataBaseURL = [appGroupDirectoryPath URLByAppendingPathComponent:#"default.realm"];
[[[RLMRealm defaultRealm]configuration]setFileURL:dataBaseURL];
RLMResults *temp = [self getContactArray]; //This gives the callKit error
RLMResults *temp ; //This doesn't give any error
[context completeRequestWithCompletionHandler:nil];
}
-(RLMResults *)getContactArray{
RLMResults *res = [[RealmContact allObjects]objectsWithPredicate:[NSPredicate predicateWithFormat:#"phone <> nil or homePhone <> nil or mobilePhone <> nil or altPhone <> nil or fax <> nil"]];
return res;
}
Why does accessing the Realm data gives the error ? The predicate format does look ok to me.
With some research I found the following code:
public enum Code : Int {
public typealias _ErrorType = CXErrorCodeCallDirectoryManagerError
case unknown
case noExtensionFound
case loadingInterrupted
case entriesOutOfOrder
case duplicateEntries
case maximumEntriesExceeded
case extensionDisabled
#available(iOS 10.3, *)
case currentlyLoading
#available(iOS 11.0, *)
case unexpectedIncrementalRemoval
}
In my case , the error says case currentlyLoading (code 7). I also tried this on realm with only 250 contacts . But I got the same error.
Edit:
If I hardcode the contact, it works fine. But if I bring Realm into scene, it fails.
CXCallDirectoryPhoneNumber phoneNumber = strtoull([#"14xxxxxx86" UTF8String], NULL, 0);
if (phoneNumber > 0) {
[context addIdentificationEntryWithNextSequentialPhoneNumber:phoneNumber label:#"Test Test"];
}
Workaround:
For now, I'm storing all my data into a file and saving that file in the app group.
NSString *appGroupId = #"group.xxx.CallerID";
NSURL *appGroupDirectoryPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId];
NSURL *appFile = [appGroupDirectoryPath URLByAppendingPathComponent:#"contacts.txt"];
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:[appFile path]];
if(exists) {
[[NSFileManager defaultManager]removeItemAtPath:[appFile path] error:nil];
}
[NSKeyedArchiver archiveRootObject:uniqueCallDirectory toFile:[appFile path]];
and accessing this array in the callID extension subclass.
The list you provide to addIdentificationEntryWithNextSequentialPhoneNumber must be ordered by ascending phone Number. Retrieve the list from realm in ascending order. (else it will break and keep the loading icon when you activate the extension)
I am trying to use standard code of keychain from Apple's sample code KeychainTouchID
Here is snippet of my code,
SecAccessControlRef sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
kSecAccessControlUserPresence, &error);
if (sacObject == NULL || error != NULL) {
NSString *errorString = [NSString stringWithFormat:#"SecItemAdd can't create sacObject: %#", error];
self.textView.text = [self.textView.text stringByAppendingString:errorString];
return;
}
// we want the operation to fail if there is an item which needs authentication so we will use
// kSecUseNoAuthenticationUI
NSDictionary *attributes = #{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrService: #"SampleService",
(id)kSecValueData: [#"SECRET_PASSWORD_TEXT" dataUsingEncoding:NSUTF8StringEncoding],
(id)kSecUseAuthenticationUI: (id)kSecUseAuthenticationUIAllow,
(id)kSecAttrAccessControl: (__bridge_transfer id)sacObject
};
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, nil);
NSString *errorString = [self keychainErrorToString:status];
NSString *message = [NSString stringWithFormat:#"SecItemAdd status: %#", errorString];
[self printMessage:message inTextView:self.textView];
});
But key chain always returns error errSecAuthFailed. Same code is code is working on one device iPhone6+ but it is not working on iPhone5 with iOS 9.x.
Tried a lot to find reason but didn't find anything useful. One important thing that I noted is that if I don't set attributed kSecAttrAccessControl then it is working fine on iPhone5 as well. so, I believe it is something related to setting access control attribute.
Any help would be appreciated,
I´m new in iOS Programming and i´m trying to receive Data from a BLE device. I´m able to connect to the device and send data to the device. The problem is receiving data from the BLE Device.
Im using this as BLE Base:
LGBluetooth
Problem:
#property (nonatomic,strong) NSString* recievedData; //data recieved from Peripheral
- (void)RecieveDataBLE:(LGPeripheral *)peripheral :(NSString*)Service_UUID :(NSString*)Characteristic_UUID {
//Function to read Data from BLE Device
[LGUtils readDataFromCharactUUID:Characteristic_UUID serviceUUID:Service_UUID
peripheral:peripheral
completion:^(NSData *data, NSError *error) {
NSLog(#"Data : %s Error : %#", (char *)[data bytes], error);
recievedData = [NSString stringWithUTF8String:[data bytes]];
}
- (IBAction)sendDOWN:(id)sender {
MessageLabel.hidden = NO;
[self RecieveDataBLE:mBuddy:SERVICE_UUID_DEVICE_INFORMATION:CHARACTERISTIC_UUID_MANUFACTURER];
MessageLabel.text = [NSString stringWithFormat:#"%#",recievedData]; //Output is always old!!
}
After the action sendDown is called, data should be read via the ReceiveDataBle function. This one will then process the data. The problem is, ReceiveDataBle is always too late, and does not receive the information immediately, but after a certain time. A callback function returns the data to ReceiveDataBle. So when the action SendDown is called the Data from the last call appears in the MessageLabel!!
The question is, how can I ensure that I have the newest data available, and not outdated data?
**You can use this type when show updated recievedData **
-(IBAction)sendDOWN:(id)sender
{
MessageLabel.hidden = NO;
[LGUtils readDataFromCharactUUID:Characteristic_UUID
serviceUUID:Service_UUID
peripheral:peripheral
completion:^(NSData *data, NSError *error) {
NSLog(#"Data : %s Error : %#", (char *)[data bytes], error);
recievedData = [NSString stringWithUTF8String:[data bytes]];
MessageLabel.text = [NSString stringWithFormat:#"%#",recievedData];
}
}
This question already has answers here:
iOS 9.3 freeze after calling openURL
(2 answers)
Closed 6 years ago.
I am using the share option in my app using UIActivityViewController; it's working fine in iOS 9.2 and Google+ share option is not working in iOS 9.3
To confirm this, I had downloaded other app which has the share option using UIActivityViewController, and the issue is the entire UI of the app is hanging up.
How can I resolve this issue?
Edit 1:
code:
NSURL * URL = [[NSURL alloc]initWithString:#"http://domainName/message.php?"];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setHTTPMethod:#"GET"];
NSString *tempEmailId = (NSString *)[[NSUserDefaults standardUserDefaults] objectForKey:CURRENT_USER_EMAIL_ID_UD_KEY];
NSString *tempPassword = (NSString *)[[NSUserDefaults standardUserDefaults] objectForKey:CURRENT_USER_PASSWORD_UD_KEY];
NSString *basicAuthCredentials = [NSString stringWithFormat:#"%#:%#", tempEmailId, tempPassword];
[request setValue:[NSString stringWithFormat:#"Basic %#", AFBase64EncodedStringFromString(basicAuthCredentials)] forHTTPHeaderField: #"Authorization"];
//NSLog(#"request %#\n",request);
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data != nil) {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSArray * activityItems = #[responseString];
dispatch_async(dispatch_get_main_queue(), ^{
activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:activities];
[activityViewController setValue:#"Today's Recommendations" forKey:#"subject"];
activityViewController.excludedActivityTypes = #[UIActivityTypePostToFacebook];
[activityViewController setCompletionWithItemsHandler:
^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"activityType: %#, returnedItems: %#, activityError: %#", activityType, returnedItems, activityError.userInfo);
if (completed)
{
NSLog(#"The Activity: %# was completed", activityType);
}
else
{
NSLog(#"The Activity: %# was NOT completed", activityType);
}
});
}];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self presentViewController:activityViewController animated:YES completion:nil];
}
//if iPad
else {
activityViewController.modalPresentationStyle = UIModalPresentationPopover;
// activityViewController.popoverPresentationController.sourceView = sender;
activityViewController.popoverPresentationController.sourceView = self.view;
if ([sender isKindOfClass:[UIButton class]]) {
UIButton *btn = (UIButton *)sender;
activityViewController.popoverPresentationController.sourceRect = btn.frame;
}
[self presentViewController:activityViewController animated:YES completion:nil];
}
});
}
}] resume];
NOTE:: Mail, Twitter, and Evernote are working. Only Google+ is hanging up.
Edit 2:: I don't know exactly but I think- its not related to open URL. If it's related then please let me know HOW?
Some JavaScript problems occurred in iOS 9.3. Its clearly mentioned in below article. Its not a code problem, it's an Apple webview problem. Check attached quote and URL for your reference.
iOS 9.3 freezes when clicking a link in an email
One of the most common problems ... affects links in emails. When using iOS 9.3, some people have found that by clicking a link in the Mail email app, the iPhone or iPad will become unresponsive.
A temporary solution is to turn off JavaScript in the Safari app by going to Settings > Safari > Advanced then turn off the toggle next to JavaScript.
This solution isn't ideal, and thankfully Apple has pushed out a new update, iOS 9.3.1 which according to the release notes "fixes an issue that caused apps to be unresponsive after tapping on links in Safari and other apps."
To download and install the update open up Settings and select General then Software Update. You should now be able to turn JavaScript back on and can click on links in emails and other messages without iOS 9.3 freezing.
Reference Link: iOS 9.3 Problems
I want to get the unique identifier which should support all iOS versions..Can any one help me on this issue. As you know that apple is deprecated the UDID method, So there is possibility to generate Unique id using wifi-mac address.But apple is going to remove the wifi mac address in iOS7 version.So my requirement is to generate a new unique code which should work in all iOS versions.Thanks in advance..
Note: Don't change the UDID once user restart the device or reinstall the application.
I was updating my application that was working based only on Unique Identifier which supported iOS 4.3 and above. So,
1) I was unable to use [UIDevice currentDevice].uniqueIdentifier; as it was no longer available
2) I could not use [UIDevice currentDevice].identifierForVendor.UUIDString because it was Available in iOS 6.0 and later only and was unable to use for lower iOS versions.
3) The mac address was not an option as it wasn't allowed in iOS-7
4) OpenUDID was deprecated some time ago and also had issues with iOS-6.
5) Advertisement identifiers were also not available for iOS-5 and below
Finally this was what i did
a) Added SFHFKeychainUtils to the project
b) Generated CFUUID key String
CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));
c) Saved it to Key Chain Utils or else it will generate a new Unique Each Time
Final Code
+ (NSString *)GetDeviceID {
NSString *udidString;
udidString = [self objectForKey:#"deviceID"];
if(!udidString)
{
CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));
CFRelease(cfuuid);
[self setObject:udidString forKey:#"deviceID"];
}
return udidString;
}
+(void) setObject:(NSString*) object forKey:(NSString*) key
{
NSString *objectString = object;
NSError *error = nil;
[SFHFKeychainUtils storeUsername:key
andPassword:objectString
forServiceName:#"LIB"
updateExisting:YES
error:&error];
if(error)
NSLog(#"%#", [error localizedDescription]);
}
+(NSString*) objectForKey:(NSString*) key
{
NSError *error = nil;
NSString *object = [SFHFKeychainUtils getPasswordForUsername:key
andServiceName:#"LIB"
error:&error];
if(error)
NSLog(#"%#", [error localizedDescription]);
return object;
}
For further Details
Now Device Identifier change to UUID.You can get UUID With the help of following code:
- (NSString *)getUUID
{
NSString *UUID = [[NSUserDefaults standardUserDefaults] objectForKey:#"uniqueID"];
if (!UUID) {
CFUUIDRef theUUID = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
UUID = [(__bridge NSString*)string stringByReplacingOccurrencesOfString:#"-"withString:#""];
[[NSUserDefaults standardUserDefaults] setValue:UUID forKey:#"uniqueID"];
}
return UUID;
}
It's Work in all iOS version.
I don't have access to the code right now (can post in a few hours if you still need it) but what I've done is create a static method 'deviceIdentifier' in a helper class.
the method does a basic check for the current iOS version, returns UDID if below 6.0 and uniqueIdentifier otherwise
Let me know if you'd like the code for that and I'll post it when I can..it's only 10-15 lines or so if I remember right but makes a big difference as then you can just call '[myHelper deviceIdentifier]' wherever you need a device ID and not have to worry about which iOS version they are using