this is the second time my Mac app has been rejected by the MAS.
I use a temporary entitlement so that the user can store his backup file the app created on his device.
This is the response I am getting from the MAS to my rejection:
We've determined that one or more temporary entitlement exceptions requested for
this app are not appropriate and will not be granted:
com.apple.security.temporary-exception.files.home-relative-path.read-write /
Very vague and the second time they are not telling me what is wrong with what i'm doing.
For that I use following entitlement:
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<string>True</string>
<key>com.apple.security.temporary-exception.files.home-relative-path.read-write</key>
<array>
<string>/</string>
</array>
And this is how I use the entitlement:
NSSavePanel* saveSelection = [NSSavePanel savePanel];
[saveSelection setPrompt:#"Export"];
[saveSelection setMessage:NSLocalizedString(#"Save your encrypted backup file to:",#"")];
[saveSelection setNameFieldStringValue:date];
[saveSelection beginSheetModalForWindow:kDelegate.window completionHandler:^(NSInteger result) {
if (result==NSFileHandlingPanelOKButton)
{....
}
}
I really do hope somebody can help and thanks a lot in advance!
I finally got it working by adding this to the NSSavePanel:
[saveSelection setAllowedFileTypes:[NSArray arrayWithObject:#"whatever"]];
[saveSelection setAllowsOtherFileTypes:NO];
I don't know why this made it work, but it does... at least in my app.
Related
I am trying to use this example: https://github.com/Azure-Samples/active-directory-b2c-xamarin-native
It have went through the tutorial 5 times and it worked with the existing fabrikamb2c but when I try to use my own b2c tenant I get errors when clicking sign in on both iOS (Safari cannot open the page because the address in invalid) and Android (blank screen) when it calls IPublicClientApplication.AcquireTokenInteractive()
For iOS - From the PublicClientApplicationBuilder logging, it's trying to go to this url:
https://mycompany.b2clogin.com/tfp/mycompany.onmicrosoft.com/b2c_1_results_mobile_app_staging/oauth2/v2.0/authorize?scope=user.read+openid+profile+offline_access&response_type=code&client_id=xxxxxxxx-yyyy-40c1-804e-13190d66ccc6&redirect_uri=msalxxxxxxxx-yyyy-40c1-804e-13190d66ccc6:%2F%2Fauth&client-request-id=ef26ee69-9f31-4b22-943b-3d497a54e580&x-client-SKU=MSAL.Xamarin.iOS&x-client-Ver=4.25.0.0&x-client-OS=14.4&x-client-DM=iPhone&prompt=select_account&code_challenge=DfZ3m6w1WX5hE4SfzlugJNMggJrAZY3H8t288cBybk8&code_challenge_method=S256&state=cf886b1c-3353-4b05-b300-bb6e1f040b672de723bb-634e-460f-bfc5-e79698061b48
but if I use this format (updated from https://learn.microsoft.com/en-us/azure/active-directory-b2c/user-flow-overview) it works
https://mycompany.b2clogin.com/mycompany.onmicrosoft.com/oauth2/v2.0/authorize?client_id=xxxxxxxx-yyyy-40c1-804e-13190d66ccc6&redirect_uri=https%3A%2F%2Fjwt.ms&response_mode=form_post&response_type=id_token&scope=openid&nonce=dummy&state=12345&p=B2C_1_results_mobile_app_staging
I don't understand why AcquireTokenInteractive() in code is putting the userflow name (B2C_1_results_mobile_app_staging) in the path part of the url while the other one puts it as querystring parameter for p...
I have the iOS Redirect URL set up in the app registration's authentication:
and here is the userflow:
Here is my pinfo.list
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.yourcompany.UserDetailsClient</string>
<key>CFBundleURLSchemes</key>
<array>
<string>msalxxxxxxxx-yyyy-40c1-804e-13190d66ccc6</string>
</array>
</dict>
</array>
anyway, any guidance would be appreciated I am quite confused by all this.. been reading docs for a few days it's not "clicking" for me. thank you.
actually it was my configuration on the authentication settings on azure - I didn't have it checked. Sheesh. I knew it was something easy. I was out in the weeds with having other redirect URIs in the Android and iOS sections ...
I have created an XPC Service .
the server side code briefly is
NSXPCListener *listener = [[NSXPCListener alloc] initWithMachServiceName:#"test.xpcserver"];
listener.delegate = delegate;
[listener resume];
this is installed as a Launch Agent using info.plist as
<?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>Label</key>
<string>TestServer</string>
<key>MachServices</key>
<dict>
<key>test.xpcserver</key>
<true/>
</dict>
<key>ProgramArguments</key>
<array>
<string>/Applications/test.app/Contents/XPCServices/xpcserver.xpc/Contents/MacOS/xpcserver</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
The server is running fine and i can see it running with launchctl list
The client side code is in another app and the code for connect is:
connection = [[NSXPCConnection alloc] initWithMachServiceName:#“test.xpcserver” options:0];
connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:#protocol(xpcserverprotocol)];
[connection resume];
service = [connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { }];
[service ServerFunc:#“howdy” withReply:^(NSString *result) {
NSLog(#"%#",result);
}];
but not able to connect to server .
any pointers as to what going wrong ?
It's hard to tell from what you've posted. Things to check:
ensure your listener delegate is implementing right function signature for shouldAcceptNewConnection(). If it's not right, you will not get any error. It should be
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)conn { your code here }
Use System Logging (NSLog) or add logging of stdout and stderr for your service. See the launch.sh in this hello_world_xpc example, which generates the plist based on local paths. That example is using the C API, so not exactly what you are looking for.
See old Objective-C hello.tar.gz example here : afewguyscoding.com/2012/07/ipc-easy-introducing-xpc-nsxpcconnection/
(Posting this for future readers, I imagine OP solved their problem by now :) )
Some other things to check:
Make sure your launch agent/deamon is using the -[NSXPCListener initWithMachServiceName], and not +[NSXPCListener serviceListener].
The latter is only useful for regular XPC service (which would be stored in the App's bundle, not in /Library/.... If you mix it up, you'll get a crash report in Console.app that will say:
Configuration error: Couldn't retrieve XPCService dictionary from service bundle.
In your agent/daemon, don't forget to start the main run loop after [listener resume]; with [[NSRunLoop currentRunLoop] run];
In your agent/daemon, make sure there's a strong reference to keep your listener's delegate alive. The -[NSXPCListener delegate] property is declared weak, so it's possible that your listener deallocates immediately after you set it. I would put an NSLog statement in the deinit of your delegate's class, just to be sure.
I'm attempting to setup a login with XamarinForms (4.1.x) and iOS (12.x) using IdentityServer (hybrid flow). I'm using the Xamarin Forms iOS example found here as a reference. After I enter my credentials, the browser tries to redirect and I get the follow error:
I'm not sure what address is invalid as nothing appears to be logged. Has anyone successfully used Xamarin.Forms with IdentityServer4 for authentication?
It seems like it's the redirect issue to your app.
Make sure you are defining the redirect url schemes properly "RedirectUri = "xamarinformsclients://callback" you have to define that Scheme in infoplist file too!
How people should answer for that kind of question:
You should use Info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.your.app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>xamarinformsclients</string>
</array>
</dict>
</array>
com.your.app is you bundle app
xamarinformsclients is your part of your RedirectUris = { "xamarinformsclients://callback" },
I am using NSAppleScript for sending email from my OSX application.
It was working fine before but now when I use new XCode 9.0 with Sierra 10.12.6 I have one problem. Application will create email and open Mail window containing email and message content but it wont perform SEND. I can click on send button and everything is fine, mail will send but I would like to avoid manual click-on-send-button action.
I am using entitlements:
<plist version="1.0">
<dict>
<key>com.apple.security.scripting-targets</key>
<dict>
<key>com.apple.mail</key>
<array>
<string>com.apple.mail.compose</string>
</array>
</dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>
And this is the code:
NSString *emailString = [NSString stringWithFormat:#"\
tell application \"Mail\"\n\
set newMessage to make new outgoing message with properties {subject:\"%#\", content:\"%#\" & return} \n\
tell newMessage\n\
set visible to false\n\
set sender to \"%#\"\n\
make new to recipient at end of to recipients with properties {name:\"%#\", address:\"%#\"}\n\
tell content\n\
",subjectt, bodyText, #"Company", toAddress, toAddress];
emailString = [emailString stringByAppendingFormat:#"\
end tell\n\
set visible to false\n\
send newMessage\n\
end tell\n\
end tell"];
NSLog(#"%#",emailString);
NSAppleScript *emailScript = [[NSAppleScript alloc] initWithSource:emailString];
[emailScript executeAndReturnError:nil];
So everything is in place but send action is failing.
Again it was working well with older OSX version(s)..
Am I missing entitlement or something?
Thank you!
It looks like you tell the newMessage to send the newMessage (double reference)
Delete newMessage in the send line
Long story short. This is the wrong way. With modern OSX use NSSharingService.
NSArray * shareItems = [NSArray arrayWithObjects:bodyText, nil];
NSArray * recepiants = [NSArray arrayWithObjects:toAddress, nil];
NSSharingService *service = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail];
[service setRecipients:recepiants];
[service setSubject:subjectt];
service.delegate = self;
[service performWithItems:shareItems];
When it comes down to sending email with some sort of results from application NSAppleScript is not your friend anymore. OSX is becoming more like iOS nowadays.
I am trying to implement a contextual menu item that would be presented in services when a text is selected. So e.g., if I select a word in a TextEdit, I want a menu item "Do my stuff" to be presented in contextual menu, which would feed the selected word to my application code for further processing.
By googling a little research, I came to conclusion that I need to implement and register a service. I tried to follow
Providing Services
documentation, but that seems at least a bit outdated (not to mention in some places vague).
From what I understood, I was able to do the following:
I implemented service object:
import Foundation
import AppKit
class ContextualMenuServiceProvider {
func importString(_ pasteBoard: Pasteboard, userData: String, error: String) {
print(">>>> in import string from service consumer")
}
}
I created an entry in Info.plist for service:
<key>NSServices</key>
<array>
<dict>
<key>NSMenuItem</key>
<dict>
<key>default</key>
<string>Import to $(PRODUCT_NAME)</string>
</dict>
<key>NSMessage</key>
<string>importString</string>
<key>NSPortName</key>
<string>MyApp</string>
<key>NSSendTypes</key>
<array>
<string>public.plain-text</string>
</array>
</dict>
</array>
And finally, I tried to register the service in AppDelegate. Now the documentation says to use:
NSApp.setServicesProvider(encryptor)
// where encryptor is an object of my ContextualMenuServiceProvider
However, it seems that NSApp does not have setServicesProvider method. I tried to use:
NSApp.servicesProvider = ContextualMenuServiceProvider()
property, however, this does not seem to work either.
I test it by running the application from the Xcode, and then, while the application is running, I try to select some text in TextEdit (it should not be restricted to TextEdit, I just use it as an example), and after right click I am looking for my menu item. It does not work.
I was able to find some kind of similar SO questions (e.g., Creating an os x service, or Howto add menu item to Mac OS Finder in Delphi XE2), but I was not able to detect what I am doing wrong from them (not to mention that most of them are old (using setServiceProvider), or using languages like C# or Delphi).
Any idea what is wrong with my code/approach?
Ok, looks like I have made several small mistakes that lead me to believe it was not working. However, in the end I was able to make it work. So if you are facing the same task, here is a solution in Swift 3:
(1) You have to implement a service method:
import Cocoa
class ServiceProvider: NSObject {
let errorMessage = NSString(string: "Could not find the text for parsing.")
#objc func service(_ pasteboard: NSPasteboard, userData: String?, error: AutoreleasingUnsafeMutablePointer<NSString>) {
guard let str = pasteboard.string(forType: NSStringPboardType) else {
error.pointee = errorMessage
return
}
let alert = NSAlert()
alert.messageText = "Hello \(str)"
alert.informativeText = "Welcome in the service"
alert.addButton(withTitle: "OK")
alert.runModal()
}
}
Here important thing that I did not know before was that the object providing the service has to subclass NSObject (it can also be ViewController, or any other NSObject subclass). Services API uses selector to call it, and selector technology works with NSObject only.
Also, service method has to have this declaration: it takes 3 arguments, first is NSPasteboard (you can use Pasteboard, but that does not provide string method) that is not labeled, second is optional String labeled userData, third is AutoreleasingUnsafeMutablePointer<NSString> labeled error. Follow this to get best type safety while still making it work. Otherwise the services API won't be able to find it and call it. You can use UnsafeRawPointers for all its arguments, but you will not gain anything by that.
(2) In the app delegate (or documentation says that you can do it anywhere, but I am doing it here) you register the service provider:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
NSApplication.shared().servicesProvider = ServiceProvider()
NSUpdateDynamicServices()
}
}
It seems to be working also without NSUpdateDynamicServices call, but I guess better be safe than sorry - it should refresh the services in the system so that you do not have to logoff and login the user to get the current service version.
(3) Finally, you have to configure the Info.plist to advertise your service method:
<key>NSServices</key>
<array>
<dict>
<key>NSMessage</key>
<string>service</string>
<key>NSPortName</key>
<string>serviceTest</string>
<key>NSMenuItem</key>
<dict>
<key>default</key>
<string>Test hello world</string>
</dict>
<key>NSRestricted</key>
<false/>
<key>NSRequiredContext</key>
<dict/>
<key>NSSendTypes</key>
<array>
<string>NSStringPboardType</string>
</array>
</dict>
</array>
This is an XML source of the Info.plist - although Apple recommends to use their editor, in Xcode 8.2 I was not able to add an NSRequiredContext key through the editor - I had to open the file as Source code and add it manually. I would recommend editing directly the XML source.
You can find the documentation about the meaning of each key in Services Properties, but I would like to mention some crucial points. First, you NEED the NSRequiredContext key - they mention it in the documentation, but the editor does not support it - edit XML directly and add it even empty (as I do). Second, if you are using NSSendTypes or NSReturnTypes and you want to work with strings, use NSStringPboardType even though its documentation says it's deprecated and should be substituted by NSPasteboardTypeString - the latter won't work. Finally, NSMessage key with service value is the name of the service method. So my service provider object declares following method:
#objc func service(_ pasteboard: NSPasteboard, userData: String?, error: AutoreleasingUnsafeMutablePointer<NSString>)
I am using the service value in NSMessage. If you want to change it (e.g., you want several service methods) just don't forget that these two has to match (value in Info.plist configuration and the name of the service method).
(4) In this state it should be working. There is one thing I would like to mention that might help you with debugging. Test it using the method mentioned in documentation at the end by running:
/Applications/TextEdit.app/Contents/MacOS/TextEdit -NSDebugServices com.mycompany.myapp
Running this from Terminal should report whether any service using provided bundle is registered, and also whether it will be presented - e.g., in my case the problem was that I had not provided the mandatory NSRequiredContext. After testing it using this approach I was able to recognise that the service was installed, and the problem was that the services API assumed it should be filtered out. After some experiments and googling I solved it by adding the empty NSRequiredContext.
After each change to the service I recommend to quit TextEdit and run it again, it seems that it keeps a reference to the old service provider object (or something like that, changes were not registered by TextEdit if I did not restart it).
The minimum requirements for text services in info.plist. All items can be added through Xcode (tested on version 14.2):
<key>NSServices</key>
<array>
<dict>
<key>NSMessage</key>
<string>message</string>
<key>NSMenuItem</key>
<dict>
<key>default</key>
<string>Title</string>
</dict>
<key>NSRequiredContext</key>
<dict/>
<key>NSSendTypes</key>
<array>
<string>NSStringPboardType</string>
</array>
</dict>
</array>
In AppDelegate:
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
NSApp.servicesProvider = self
}
#objc func message(_ pasteboard: NSPasteboard, userData: String?, error: NSErrorPointer) {
guard let content = pasteboard.string(forType: .string) else { return }
// Use `content`…
}
}
The system won’t update services every time after app’s launching. Remove the app entirely, then build and run again so the services can be refreshed. Run pbs to check if the service is correctly configured under your bundle identifier:
/System/Library/CoreServices/pbs -dump_pboard