I have a x86_64 app that I would like to have optionally read Skype status messages. However, the 5 year old skype mac framework is 32-bit, and if there is a way to have that compile within a 64-bit app, I haven't found it.
My question is, basically, how should I go about doing this? I really only need to get and set the USERSTATUS AWAY/ONLINE string.
Using AppleScript, a "Should Skype allow this" dialog pops up... every time. This is highly inefficient and downright irritating.
Advice?
I'm considering writing a 32-bit CLI wrapper, but that seems like overkill.
I used Notification Watcher to learn that Skype's API just works with NSDistributedNotifications. Repeating those notifications worked like a charm for a 64bit app.
Check out Scripting Bridge: Introduction to Scripting Bridge Programming Guide for Cocoa
If I remember right, the permission dialog does not come up once you allow permission.
I my Skype Apple Scripts I have to GUI to click them. If they come up.
tell application "Skype" to launch
delay 15
(* this part if the security API window comes up*)
tell application "System Events"
tell application process "Skype"
if exists (radio button "Allow this application to use Skype" of radio group 1 of window "Skype API Security") then
click
delay 0.5
click button "OK" of window "Skype API Security"
end if
end tell
end tell
delay 5
I've found out that if you open "Skype.app" by viewing bundle contents -> Frameworks you'll find a 64bit and 32bit skype.framework
This is an answer in reply to a request from twitter. I used this code after asking this question way back when. I have not needed to look into the Skype API since this works just fine, but I imagine that its been updated since I last tried to use it. Anyhow...
Here's a list of the NSDistributedNotifications that I use when communicating to skype:
SKSkypeAPINotification
SKSkypeAttachResponse
SKSkypeBecameAvailable
SKAvailabilityUpdate
SKSkypeWillQuit
Just like any other kind of NSDistributedNotification, you simply register and process the results:
[[NSDistributedNotificationCenter defaultCenter]
addObserver:self selector:#selector(setStatusAfterQuit:)
name:#"SKSkypeWillQuit"
object:nil
suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
These are the iVars that I keep to sync with Skype:
NSString *applicationName;
NSString *mostRecentStatus;
NSString *mostRecentStatusMessage;
NSString *mostRecentUsername;
int APIClientID;
BOOL isConnected;
BOOL needToSetMessage;
NSString *nextMessage;
NSString *nextStatus;
Here's an example of how to connect to skype:
-(void) skypeConnect{
if (!isConnected){
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:#"SKSkypeAPIAvailabilityRequest"
object:nil
userInfo:nil
deliverImmediately:YES];
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:#"SKSkypeAPIAttachRequest"
object:applicationName
userInfo:nil
deliverImmediately:YES];
}
}
Here's an example of getting the status message (after you've registered with Skype):
-(void) processNotification:(NSNotification *) note{
if ([[note name] isEqualToString:#"SKSkypeAttachResponse"]){
if([[[note userInfo] objectForKey:#"SKYPE_API_ATTACH_RESPONSE"] intValue] == 0){
NSLog(#"Failed to connect to Skype.");
isConnected = NO;
}else {
NSLog(#"Connected to Skype.");
APIClientID = [[[note userInfo] objectForKey:#"SKYPE_API_ATTACH_RESPONSE"] intValue];
isConnected = YES;
[self sendCommand:#"GET PROFILE MOOD_TEXT"];
if (needToSetMessage){
[self sendCommand:[NSString stringWithFormat:#"SET USERSTATUS %#",nextStatus]];
[self sendCommand:[NSString stringWithFormat:#"SET PROFILE MOOD_TEXT %#",nextMessage]];
needToSetMessage = NO;
nextMessage = #"";
nextStatus = #"";
}
}
}
}
Related
I'm trying to (programmatically) detect the OSX administrator password prompt that appears when changing system security settings. Ideally the solutions would work for C++ or Objective-C. I've looked at various NSDistributedNotificationCenters that provide OS notifications, but none of them seem to be specific to the password prompt. I've tried registering for all notifications that the OS can provide, but these notifications seem to stop once I've entered the System Preferences window.
I've also looked into the SFAuthorizationPlugin concept, but it seems like that's more for logging into the system from a cold boot.
I know it is possible, as I've seen other applications detect the password prompt and display something on the screen whenever it appears.
So how can I programmatically detect the OSX administrator password prompt?
You can listen for SecurityAgent notifications from the workspace.
Subscribe to application activation notifications like so:
#interface notificationHandler: NSObject {}
#end
#implementation notificationHandler
-(id)init
{
[[[NSWorkspace sharedWorkspace] notificationCenter]
addObserver:self
selector :#selector(handleNotification)
name :NSWorkspaceDidActivateApplicationNotification
object :nil];
} // init
-(void)handleNotification:(NSNotification *) notification
{
NSDictionary info = [notification userInfo];
NSString *appName = [[info objectForKey:NSWorkspaceApplicationKey] localizedName];
if ([appName isEqualToString:#"SecurityAgent"]) {
// You have found the administrator password prompt!
}
} // handleNotification
#end
I have two cocoa apps. Application1 calls Application2(abc.app) as below-
if ([[NSWorkspace sharedWorkspace] respondsToSelector:#selector(launchApplicationAtURL:options:configuration:error:)])
return nil != [[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:#"abc.app" isDirectory:NO] options:NSWorkspaceLaunchDefault configuration:nil error:NULL];
This should open Application2 (abc.app). Now If application 1 calls application 2 again, I want to activate abc.app (If this is minimised in the dock).I want to ensure there is single instance of abc.app running. How can we achieve this?
Not quite sure of your problem. Mac OS X by default only launches one instance of an app. (Unless you have several physical copies of the executable on disk, but even for that case there's an Info.plist key that prohibits launching an app if one with the same bundle ID is already running).
Also, by default, NSWorkspace should bring to front and un-collapse your application if it has no other windows open (it should behave as if you'd double-clicked it again in Finder, or clicked its dock icon when it's already running), and it will call the second app's 'reopen application' handler.
If it doesn't do it, you could try to explicitly un-collapse your main window from the 'reopen' delegate method, or if you don't want this to happen generally (but why wouldn't you?), you could look into sending an Apple Event between the two applications.
Also, you can check if the second application is already running by looking at the runningApplications and looking for an entry with the same bundle ID.
You can check if your second application is running and check if it's the active application (frontmost) with NSRunningApplicationclass.
// check if abc.app is running
NSArray *apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:#"com.youApplication.abc"];
if ([apps count] == 0)
{
// not running, launch it
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:#"abc.app" isDirectory:NO] options:NSWorkspaceLaunchDefault configuration:nil error:NULL];
}
// check if abc.app is frontmost
NSArray *apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:#"com.youApplication.abc"];
if ([apps count])
{
// abc.app is running, check if active
if (![(NSRunningApplication*)[apps objectAtIndex:0] isActive])
{
// not active, activate it
[(NSRunningApplication*)[apps objectAtIndex:0] activateWithOptions: NSApplicationActivateAllWindows];
}
}
You canĀ“t from App1. You can check if your App2 is launched from App2 with Notifications like here
I would like to detect when a user refused the microphone permission on my iOS application.
I only get this value when I try to record the microphone: -120.000000 db
But before to get this I have to set up an AVAudioSession. Is there another function?
And I got this message in the output:
Microphone input permission refused - will record only silence
Thanks.
If you are still compiling with iOS SDK 6.0 (as I am) you have to be a bit more indirect than #Luis E. Prado, as the requestRecordPermission method doesn't exist.
Here's how I did it. Remove the autorelease bit if you're using ARC. On iOS6 nothing happens, and on iOS7 either the 'microphone is enabled' message is logged or the alert is popped up.
AVAudioSession *session = [AVAudioSession sharedInstance];
if ([session respondsToSelector:#selector(requestRecordPermission:)]) {
[session performSelector:#selector(requestRecordPermission:) withObject:^(BOOL granted) {
if (granted) {
// Microphone enabled code
NSLog(#"Microphone is enabled..");
}
else {
// Microphone disabled code
NSLog(#"Microphone is disabled..");
// We're in a background thread here, so jump to main thread to do UI work.
dispatch_async(dispatch_get_main_queue(), ^{
[[[[UIAlertView alloc] initWithTitle:#"Microphone Access Denied"
message:#"This app requires access to your device's Microphone.\n\nPlease enable Microphone access for this app in Settings / Privacy / Microphone"
delegate:nil
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil] autorelease] show];
});
}
}];
}
EDIT: It turns out that the withObject block is executed in a background thread, so DO NOT do any UI work in there, or your app may hang. I've adjusted the code above. A client pointed this out on what was thankfully a beta release. Apologies for the mistake.
Please note that this will only work if built with Xcode 5, and not with 4.6
Add the AVFoundation Framework to your project
Then import the AVAudioSession header file, from the AVFoundation framework, where you intend to check if the microphone setting is enabled
#import <AVFoundation/AVAudioSession.h>
Then simply call this method
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
if (granted) {
// Microphone enabled code
}
else {
// Microphone disabled code
}
}];
The first time this method runs, it will show the prompt to allow microphone access and based on the users response it will execute the completion block. From the second time onwards it will just act based on the stored setting on the device.
Swift answer:
if AVAudioSession.sharedInstance().recordPermission() == .Denied {
print("Microphone permission refused");
}
Or you can use framework like PermissionScope which permit to easily check permissions. https://github.com/nickoneill/PermissionScope
Edit: Swift 3 answer:
import AVFoundation
...
if AVAudioSession.sharedInstance().recordPermission() == .denied {
print("Microphone permission refused");
}
I'm not 100% certain if we're allowed to talk about iOS 7 outside of Apple's devforums, but I found the answer you're looking for there.
In short, you'll find your solution in the AVAudioSession.h header file in the SDK. And if you want to make use of it while still supporting iOS 6, make certain to use "respondsToSelector:" to check for the API availability.
Is there a way (some API) to get the list of installed apps on an iPhone device.
While searching for similar questions, I found some thing related to url registration, but I think there must be some API to do this, as I don't want to do any thing with the app, I just want the list.
No, apps are sandboxed and Apple-accepted APIs do not include anything that would let you do that.
You can, however, test whether a certain app is installed:
if the app is known to handle URLs of a certain type
by using [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"thisapp://foo"]
You can get a list of apps and URL schemes from here.
For jailbroken devices you can use next snipped of code:
-(void)appInstalledList
{
static NSString* const path = #"/private/var/mobile/Library/Caches/com.apple.mobile.installation.plist";
NSDictionary *cacheDict = nil;
BOOL isDir = NO;
if ([[NSFileManager defaultManager] fileExistsAtPath: path isDirectory: &isDir] && !isDir)
{
cacheDict = [NSDictionary dictionaryWithContentsOfFile: path];
NSDictionary *system = [cacheDict objectForKey: #"System"]; // First check all system (jailbroken) apps
for (NSString *key in system)
{
NSLog(#"%#",key);
}
NSDictionary *user = [cacheDict objectForKey: #"User"]; // Then all the user (App Store /var/mobile/Applications) apps
for (NSString *key in user)
{
NSLog(#"%#",key);
}
return;
}
NSLog(#"can not find installed app plist");
}
for non jailbroken device, we can use third party framework which is called "ihaspp", also its free and apple accepted. Also they given good documentation how to integrate and how to use. May be this would be helpful to you. Good luck!!
https://github.com/danielamitay/iHasApp
You could do this by using the following:
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector = NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSMutableArray *Allapps = [workspace performSelector:selectorALL];
NSLog(#"apps: %#", Allapps);
And then by accessing each element and splitting it you can get your app name, and even the Bundle Identifier, too.
Well, not sure if this was available back when the last answer was given or not (Prior to iOS 6)
Also this one is time intensive, yet simple:
Go into settings > Gen. >usage. The first category under usage at least right now is Storage.
It will show a partial list of apps. At the bottom of this partial list is a button that says "show all apps".
Tap that and you'll have to go through screen by screen, and take screenshots (Quick lock button and home button takes a screenshot).
I'm doing this now and I have hundreds of apps on my iPhone. So it's going to take me a while. But at least at the end of the process I'll have Images of all my apps.
I am sure it's something easy, and I am not looking to the right documentation.
I need to get information about the application that handles the active window. The code I need to write needs to intercept some custom gestures, and return to the application an event that depends from the application itself.
There's the NSWorkspace class from which you can get a dictionary with information about the activeApplication. That application usually owns the "key" window.
Edit: For apps targeting 10.6 or later, activeApplication is deprecated. Here's the new way to go:
NSRunningApplication *activeApplication = nil;
for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications]) {
if (app.active) {
activeApplication = app;
break;
}
}
Method activeApplication is deprecated from MacOS 10.7. Documentation suggests to use NSRunningApplication instead.