Mac custom protocol fails on some machines - objective-c

Mac OS 10.8.3. This simple app runs from a custom protocol when clicking a link in the browser, for example run .
Compiled the .app with xCode, unsigned.
Works on most machines but not on some. One that doesn't work is Mac OS 10.8.2 with the gatekeeper OFF. It gives the error "failed for weird reason (13)". I guess this has got to do with permission or security. I tried chmoding Contents/MacOS/Binary to 777, but still the same.
Do I have to sign it will Apple dev certificate to make it work, or do something else in the code or plist to make it work on all machines?
plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>protocoltest</string>
</array>
<key>CFBundleURLName</key>
<string>com.TestWebLauncher</string>
</dict>
</array>
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
if ([invokeUrl length] == 0)
{
invokeUrl = #"no url";
}
[txt setStringValue:invokeUrl];
}
- (id)init
{
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:#selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
return [super init];
}
- (BOOL)handleURLEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent
{
NSString* url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
NSLog(#"%#", url);
invokeUrl = url;
return YES;
}
#end

Related

MacOS notifications hidden in notification center when app is focused

I'm writing standalone Objective-C code to display notifications on MacOS. Here's what I have so far.
The main logic is in notify.m:
#import <stdio.h>
#import <Cocoa/Cocoa.h>
#import <UserNotifications/UserNotifications.h>
#import <objc/runtime.h>
#interface AppDelegate : NSObject<NSUserNotificationCenterDelegate>
#end
#implementation AppDelegate
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
shouldPresentNotification:(NSUserNotification *)notification {
return YES;
}
#end
int native_show_notification(char *title, char *msg) {
NSApplication *app = [NSApplication sharedApplication];
AppDelegate *appdel = [[AppDelegate alloc] init];
app.delegate = appdel;
NSUserNotificationCenter *nc = [NSUserNotificationCenter defaultUserNotificationCenter];
nc.delegate = appdel;
NSUserNotification *n = [[NSUserNotification alloc] init];
n.title = [NSString stringWithUTF8String:title];
n.informativeText = [NSString stringWithUTF8String:msg];
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:n];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
return 0;
}
int main() {
const int a = 50, b = 150;
char title[a] = "Test\0", msg[b] = "Hello!\0";
native_show_notification(title, msg);
}
Along with the code, we have an Info.plist in the same directory.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.microsoft.VSCode</string>
</dict>
</plist>
The compilation command is simple: cc -framework Cocoa -o app notif.m. The Info.plist is discovered and incorporated automatically.
This code works fine, with one caveat. If the application defined by the package name (in this case com.microsoft.VSCode) is focused, the notification is not "pushed" to the user under default settings [1]. Instead it is hidden in the notification center. When the application in question is not focused, though, the notification is pushed properly. If you want to test this yourself, try compiling and running the code in VSCode, where it seems like nothing happened until you check your notification center. Then set the <string> to something like com.apple.calendar. It'll work.
How can I avoid this and get the notification to display no matter what?
[1] The default notification scheme is "Banner". The problem goes away when the user selects "Alert", but I cannot expect this. I'd like to get it working with Banner too.

How can i receive Messages in voip?

How can I receive Messages in voip? I can get the Voip Token!
I'm writing in Objective C:
I have searched around the internet but can't find any solutions! All I found is Swift, but can't get the token in Swift. In Objective C I can get token but not get Messages from a line.
apn push "<Token>" -c backgroundfetch.pem -m "Hello"
How can I popup a Messages in Objective C? Here is my code:
#import "AppDelegate.h"
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import PushKit;
#import UserNotifications;
#interface AppDelegate ()
#end
#implementation AppDelegate
NSString *fcmToken = #"";
// Trigger VoIP registration on launch
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self voipRegistration];
return YES;
}
// Register for VoIP notifications
- (void) voipRegistration {
dispatch_queue_t mainQueue = dispatch_get_main_queue();
// Create a push registry object
PKPushRegistry * voipRegistry = [[PKPushRegistry alloc] initWithQueue: mainQueue];
// Set the registry's delegate to self
voipRegistry.delegate = self;
// Set the push type to VoIP
voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{
if([credentials.token length] == 0) {
NSLog(#"voip token NULL");
return;
}
NSLog(#"PushCredentials: %#", credentials.token);
}
// Handle incoming pushes
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {
// Process the received push
NSLog(#"Get");
}
#end
My info.plist:
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
<string>audio</string>
<string>fetch</string>
<string>remote-notification</string>
</array>
In your case the solution is to send a silent push notification. Once the silent push notification arrives, execute your code with background task.
Here is the good explanations for sending a silent push notification.
https://stackoverflow.com/a/36327058/9106403

How to read infos from /S/L/E kext info.plist file?

I’m just a newbie in Mac OS X programming so please, be patient with me. I’m trying to make a cocoa app which the goal is to read some infos from Info.plist kext’s file, which the full path is /System/Library/Extensions/NVDAResman.kext/Contents/Info.plist
h.
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (weak) IBOutlet NSTextField *nvidiaNameTextField;
#end
m.
#import "AppDelegate.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
[self setnvidiaNameTextField];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
// This will allow the application to quit instead of just closing the window
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return YES;
}
// Find NVIDIA Kernel Extension Name
-(void)setnvidiaNameTextField
{
NSString *nvidiaNameTextField = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleName"];
self.nvidiaNameTextField.stringValue = [NSString stringWithFormat:#"%#", nvidiaNameTextField];
}
#end
it works but with my project Info.plist file, and it’s not what I want.
So my question is how can I read Info.plist from NVDAResman.kext?
Thank you in advance
PS: I’m using Xcode 7.1 beta (7B60)
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:#"/System/Library/Extensions/NVDAResman.kext/Contents/Info.plist"];
Please mind that any search using "[NSBundle mainBundle]" will results within your application package (under .app folder structure). Also if you plan to sandbox your application the above code will not work and there is no solution to make it work with Sandboxing (security of OS X platform).
here’s how I did it (thanks to xhruso00)
m.
// Find NVIDIA Kernel Extension Name
-(void)setnvidiaVersionTextField
{
NSDictionary *infoDict = [[NSDictionary alloc] initWithContentsOfFile:#"/System/Library/Extensions/NVDAResman.kext/Contents/Info.plist"];
NSString* nvidiaVersionTextField = [infoDict objectForKey:#"CFBundleName"];
self.nvidiaVersionTextField.stringValue = [NSString stringWithFormat:#"%#", nvidiaVersionTextField];
}

Better way to override atomic property setter for ARC and thread-safe in Objective-C

I have a class containing enum property, and I want to init its instances from plist file using method setValuesForKeysWithDictionary:. But the file may contain invalid values. The scenario is as follows:
In the file 'MyClass.h':
typedef NS_ENUM(NSInteger, FruitTag) {
Apple = 0,
Banana = 1,
Orange = 2,
Unknown = 3
};
#interface MyClass : NSObject
#property (strong, nonatomic) NSString *name;
#property FruitTag tag;
#end
the plist file:
<plist version="1.0">
<array>
<dict>
<key>name</key>
<string>Apple</string>
<key>tag</key>
<integer>0</integer>
</dict>
<dict>
<key>name</key>
<string>Banana</string>
<key>tag</key>
<string>1</string>
</dict>
<dict>
<key>name</key>
<string>Pineapple</string>
<key>tag</key>
<string>5</string>
</dict>
</array>
</plist>
As you see, the last key value '5' is invalid for the max enum value is '3'! But the method setValuesForKeysWithDictionary: just set the value, no matter valid or not. So I want to override the setter, but the enum property is atomic! One more thing is: I want its getter and setter be safe in multi-thread scenario. Thinking about the two, I modified the code as:
In the file 'Myclass.h':
typedef NS_ENUM(NSInteger, FruitTag) {
Apple = 0,
Banana = 1,
Orange = 2,
Unknown = 3
};
#interface MyClass : NSObject
#property (strong, nonatomic) NSString *name;
//#property FruitTag tag;
- (FruitTag)tag;
- (void)setTag:(NSInteger)aTag;
#end
And in the file 'Myclass.m':
#import "MyClass.h"
#implementation MyClass
{
FruitTag tag;
}
- (FruitTag)tag
{
#synchronized (self) {
return tag;
}
}
- (void)setTag:(NSInteger)aTag
{
#synchronized (self) {
if ((aTag < Apple) || (aTag > Unknown)) {
tag = Unknown;
} else {
tag = aTag;
}
}
}
- (void)print
{
#synchronized (self) {
NSLog(#"the tag is: %d", tag);
}
}
#end
Hmm, it looks odd, but does work as I test using the method setValuesForKeysWithDictionary:. But I am not sure about it: is it ok? thread-safe enough? any potential risk? or a better way to override is more welcome! thanks!
Why do you think it looks odd? You've just manually implemented a "property" and added simple bounds checking – a good reason to implement a property yourself.
Is it thread-safe enough? Well it either is or it isn't, and #synchronized certainly makes it so. There might be more efficient, lower-level, ways of making the operations thread-safe; or you might even discover that it is "enough" to do nothing special; but unless you've identified a performance issue there is no need to go there - the code is simple and your intentions are clear.
HTH
I would recommend on such implementation:
#property (nonatomic, strong) dispatch_queue_t atomicSyncQueue;
#synthesize tag = _tag;
// #init time
_atomicSyncQueue = dispatch_queue_create("com.YOUR_DEBUG_INFO", DISPATCH_QUEUE_SERIAL);
- (NSInteger)tag {
__block NSInteger result = NO;
dispatch_sync(self.atomicSyncQueue, ^{
result = _tag;
});
return result;
}
- (void)setTag:(NSInteger)value {
dispatch_async(self.atomicSyncQueue, ^{
if (self->_tag != tag) {
self->_tag = tag;
// custom code:
}
});
}

How to use custom URL scheme to send Get URL event to running application?

My Cocoa application needs to handle Get URL events. I think I correctly followed the steps in this answer to modify Info.plist and write & register a URL handler method.
Problems:
When I go mytesturl://anything in Safari while my app is running, it pops up a window asking if I want to open my app. And if I say yes, nothing seems to happen except that an icon appears for an instant in the dock. So it might be trying to launch another instance of my app instead of sending a message to the running instance?
When I do the same in Firefox, it pops up a window asking me to choose an application. So custom URL protocols are not expected to work in all browsers?
Info.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
...
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>My test URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>mytesturl</string>
</array>
</dict>
</array>
...
</dict>
</plist>
Source code:
#import <Cocoa/Cocoa.h>
#include <stdio.h>
#interface Test : NSObject
{
}
- (void)test;
- (void)handleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
#end
#implementation Test
- (void)test
{
NSLog(#"Started...");
char c;
scanf("%c", &c);
}
- (void)handleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
NSURL *url = [NSURL URLWithString:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]];
NSLog(#"url = %#", url);
}
#end
int main(int argc, char *argv[])
{
Test *app=[[Test alloc] init];
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:app andSelector:#selector(handleEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
[app test];
return 0;
}
NSAppleEventManager requires an NSApplication instance in order to function.
Try making Test a subclass of NSApplication, and change main to something like this:
id app = [NSApplication sharedApplication];
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:app andSelector:#selector(handleEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
[app run];