How do I create a WKWebView App for MacOS - macos

I have an HTML5 App developed in XCode in the IOS App Store and I wish to create a copy of that app for the Mac App Store.
I thought this would be easy but I cannot find any easy tutorials to follow, certainly not using XCode 11 and Swift 5.1. I do not want to go down the automated route provided in Mac OS 10.15
When I built the default Hello World App that comes with XCode 11, it will not run on 10.14! I do not want to upgrade to 10.15 yet, primarily because I want the app to work on earlier versions of MacOS
Anyone who can provide me with a reference to a working example of a WKWebView App loading local files that runs in XCode 11 on Max OS 10.14 will be my hero.

Step 1 - Install XCode 11 and open it.
Step 2 - Select "File" and "New" and "Project" from the main menu.
Step 3 - Select "App" (top left) and Select "Next" (bottom right).
Step 4 - Give your app a name, for User Interface select "Storyboard" and then select "Next".
Step 5 - Select a folder for where to store your new app on your computer and select "Create".
Step 6 - In XCode Navigator (left hand pane) select "Add Files" from the context menu.
Step 7 - Select the folder containing your html/javascript/css/image files - in this example I assume the folder will have the name "www" but it can be anything - just remember to change "www" in the code shown below to what you want.
Step 8 - Select "Create folder references for any added folders" and select "Add"
Step 9 - Select "ViewController.swift" from the Navigator pane and replace everything with with code shown below, changing "www" to the folder name containing your html etc and changing "AppName" to the name of your html file.
Step 10 - Press "Run" and use your new app.
For how to publish it and add other functionality (such as in app purchases) refer to Apple Developer and other internet resources/stack overflow questions.
import Cocoa
import WebKit
class ViewController: NSViewController, WKUIDelegate
{
var webView: WKWebView!
override func loadView()
{
let webConfiguration = WKWebViewConfiguration ();
webConfiguration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs");
webView = WKWebView (frame: CGRect(x:0, y:0, width:800, height:600), configuration:webConfiguration);
webView.uiDelegate = self ;
view = webView;
}
override func viewDidLoad() {
super.viewDidLoad()
if let url = Bundle.main.url ( forResource: "AppName"
, withExtension: "html"
, subdirectory: "www")
{
let path = url.deletingLastPathComponent();
self.webView.loadFileURL ( url
, allowingReadAccessTo: path);
self.view = webView ;
}
}
}

Using Xcode 12 and Big Sur I had to go to the project properties, select the Signing & Capabilities tab, and check Outgoing Connections (Client) under the App Sandbox to get the excellent answer from Steve Brooker to work.

Related

Xcode 13 will not show Preview

I have a brand new 21 Macbook Pro with the M1 Pro chip. I installed Xcode from the app store, and I have also installed Xcode beta. I am completely up to date on Monterey as well.
I am building a swift UI app and I cannot get preview to work at all.
I get the following error.
== PREVIEW UPDATE ERROR:
MessageSendFailure: Message send failure for send previewInstances message to agent
==================================
| RemoteHumanReadableError
|
| LoadingError: failed to load library at path "/Users/user/Library/Developer/Xcode/DerivedData/Test-gfnknimtrrhvztavjffxvzjvrvmo/Build/Intermediates.noindex/Previews/Test/Intermediates.noindex/Test.build/Debug-iphonesimulator/Test.build/Objects-normal/arm64/SwiftUIView.2.preview-thunk.dylib": Optional(dlopen(/Users/user/Library/Developer/Xcode/DerivedData/Test-gfnknimtrrhvztavjffxvzjvrvmo/Build/Intermediates.noindex/Previews/Test/Intermediates.noindex/Test.build/Debug-iphonesimulator/Test.build/Objects-normal/arm64/SwiftUIView.2.preview-thunk.dylib, 0x0002): tried: '/Users/brandon/Library/Developer/Xcode/DerivedData/Test-gfnknimtrrhvztavjffxvzjvrvmo/Build/Intermediates.noindex/Previews/Test/Products/Debug-iphonesimulator/SwiftUIView.2.preview-thunk.dylib' (no such file), '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/Users/user/Library/Developer/Xcode/DerivedData/Test-gfnknimtrrhvztavjffxvzjvrvmo/Build/Intermediates.noindex/Previews/Test/Intermediates.noindex/Test.build/Debug-iphonesimulator/Test.build/Objects-normal/arm64/SwiftUIView.2.preview-thunk.dylib' (no such file), '/Users/user/Library/Developer/Xcode/DerivedData/Test-gfnknimtrrhvztavjffxvzjvrvmo/Build/Intermediates.noindex/Previews/Test/Intermediates.noindex/Test.build/Debug-iphonesimulator/Test.build/Objects-normal/arm64/SwiftUIView.2.preview-thunk.dylib' (no such file), '/usr/lib/SwiftUIView.2.preview-thunk.dylib' (no such file))
I have tried to reinstall xcode, reboot you name it.
I can get simulator to work...
Any ideas?
Nothing I tried worked, including running:
sudo xcodebuild -license in the terminal
Deleting derived data
Sign in again to GitHub
Restarts
Only when I toggled Automatically refresh canvas (Editor > Canvas) I got preview back.
Preview was failing on a new default projects as well.
I had the same problem and found a solution here:
https://developer.apple.com/forums/thread/691237
I was not signed in to GitHub so as suspected, it does not play a role.
It seems Xcode got in to an invalid state. I suspect that simply disabling and enabling automatic signing would resolve the issue but I also cleared the Container folder for my project as suggested in the post.
Same issue and resolved it by change Mac's user name to lowercase.
Username->username
I had the same problem because I downloaded a GitHub project (an existing SwiftUI project) and I didn't create a new SwiftUI project from scratch. I notice the SwiftUI view doesn't had the PreviewProvider struct at the bottom:
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView()
}
}
After adding the PreviewProvider struct, Xcode showed the Preview.

Open Notification Center programmatically on OS X

Is there a way to open Notification Center on OS X from a Cocoa app?
We tried launching the Notification Center app, but that doesn't work.
Our app is not sandboxed, so we can do whatever is required.
You can open it using ScriptingBridge, but it's not an official API, so it might break someday.
It's a bit odd, but this only works with sandboxed apps. If your app is not sandboxed, you need Accessibility access.
1. Generate Header file
Open Terminal and run the following commands:
cd ~/Desktop/
sdef /System/Library/CoreServices/System\ Events.app | sdp -fh --basename SystemEvents
Copy the file "SystemEvents.h" from your Desktop into your project.
Xcode will show some errors or warnings for a few lines in this file. Just remove these lines.
2. Import ScriptingBridge framework and generated header file.
#import <ScriptingBridge/ScriptingBridge.h>
and
#import "SystemEvents.h"
3. Add code
SystemEventsApplication *systemEventsApp = (SystemEventsApplication *)[[SBApplication alloc] initWithBundleIdentifier:#"com.apple.systemevents"];
SystemEventsApplicationProcess *sysUIServer = [systemEventsApp.applicationProcesses objectWithName:#"SystemUIServer"];
SystemEventsMenuBarItem *item = nil;
for (SystemEventsMenuBar *menuBar in sysUIServer.menuBars) {
item = [menuBar.menuBarItems objectWithName:#"Notification Center"];
if (item != nil && [item.name isEqualToString:#"Notification Center"])
break;
}
[item clickAt:nil];
You can also replace line 4-9 with this code, if you're sure the menu bars won't change in the future:
SystemEventsMenuBarItem *item = [[[sysUIServer.menuBars objectAtLocation:#2] menuBarItems] objectWithName:#"Notification Center"];
4. Add temporary exception for sandbox
Open your projects .entitlements file and add "com.apple.security.temporary-exception.apple-events" as an array. Add "com.apple.systemevents" as String.
Switching to Today view
This requires your app to have Accessibility access, so it won't work in sandboxed apps. You can simply call this script instead of using ScriptingBridge:
tell application "System Events"
click menu bar item "Notification Center" of menu bar 2 of application process "SystemUIServer"
click radio button "Today" of radio group 1 of window "NotificationTableWindow" of application process "NotificationCenter"
end tell
No, unfortunately there is no support for opening the Notification Center. Supposedly because it wouldn't be annoying for the user to have it open without them wanting it to open

Xamarin: Visual Studio Start iOS app always terminates (found work-around)

Xamarin Noob
Xamarin.Forms Noob
I am all hooked up. Business license on iOS and Android and developing from VS 2013.
I created the initial sample from the Xamarin Intro to Forms.
I 'Start'ed the app and it ran fine on my Mac. I saw the 'Hello, Forms !' label in the running app in the iOS simulator on my Mac Build Machine.
I then replaced the following code in my App.cs
public static Page GetMainPage()
{
return new ContentPage
{
Content = new Label
{
Text = "Hello, Forms !",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
},
};
}
with:
public static Page GetMainPage()
{
return new ContentPage()
{
Content = new StackLayout
{
Spacing = 10,
Children =
{
new Label
{
Text = "Stop",
BackgroundColor = Color.Red,
Font = Font.SystemFontOfSize(20)
},
new Label
{
Text = "Slow down",
BackgroundColor = Color.Yellow,
Font = Font.SystemFontOfSize(20)
},
new Label
{
Text = "Go",
BackgroundColor = Color.Green,
Font = Font.SystemFontOfSize(20)
}
}
}
};
}
That's all I did, but now the app will not run in the simulator - it always exists as soon as it starts...
I put the original code back again, and it still doesn't start.
I always see (in My VS 12013 Mac Server Log)
[10-Nov-2014 15:43:32] Request handled in 4.129ms
[10-Nov-2014 15:43:37] Request handled in 3.728ms
[10-Nov-2014 15:43:40] stdout: Starting iPhone 5s
Launching application
Application launched. PID = 2872
Press enter to terminate the application
>
Application Terminated
[10-Nov-2014 15:43:42] Request handled in 3.898ms
[10-Nov-2014 15:43:48] Request handled in 4.031ms
etc....
I have exited both the iOS simulator and VS 2013, paired them again, all to no avail...
What could possibly be wrong?
EDIT
Infact, when the app becomes visible in the simulators view of icons, clicking it brings up the original version of "Hello, Forms!" - so my new code is never deployed to the simulator...
EDIT 2
Ok, I got the new content moving and got it running:
I had to manually "Reset content on device" in the iOS simulator on the Mac.
I also had to manually clean each project in VS 2013 - just rebuilding the solution doesn't do anything to the content being sent to the Mac iOS simulator server, I guess.
I hope this helps someone as new as I am.
Try removing "." from your app's name in Info.plist file.
After fiddling..
The way to fix this is to change the build config on the solution.
In a fresh Xamarin.Forms solution in Visual Studio, you might have:
Solution 'MyXFormsSample' (3 projects)
v MyXFormsSample (Portable)
> Properties
> References
> App.cs
packages.config
> MyXFormsSample.Android
> MyXFormsSample.iOS
It seems that by default, in the solution's Configuration Manager's build configuration, the portable code project is not set to build for the iPhoneSimulator platform
I clicked that on for the debug, and also release, solution configurations, and still I had to Reset Content on the Mac's iOS simulator before debugging, then all I had to do was press the green 'Start' button in the menu - all was updated and released to the Mac Build server's iOS Simulator.

Open document by dropping it on document-based application icon in OS X

I'm making a document-based application where documents are application bundles.
I can open them through "File → Open" menu fine. But when I try to drop them on the Dock icon they get rejected and the icon doesn't highlight.
I've searched this issue and it seems like it should just work given that LSItemContentTypes property is specified. Here is my Info.plist excerpt:
CFBundleDocumentTypes = (
{ CFBundleTypeName = "Example";
CFBundleTypeRole = "Editor";
LSHandlerRank = "Alternate";
LSItemContentTypes = ( "com.apple.application-bundle" );
NSDocumentClass = "Example";
NSExportableTypes = ( "com.apple.application-bundle" );
},
);
(I am developing outside of Xcode, this is a TextMate-formatted plist file.)
Also I tried implementing application:openFile: and application:openFiles: on my app delegate but they never get called.
There are no warnings or other related messages in the log. What am I missing?
Perhaps you need to set LSTypeIsPackage to YES.
That's the only difference I see with your plist stuff and mine that opens packages.
After that, maybe you need to logout/login, restart the app, or whatever to "refresh the system/launch services"?

Cocoa button opens a System Preference page

In a OSX Cocoa app, I would like a button that would open the "speech" preference pane. Is that possible? I'm just trying to save them the time to go System Preferences > Speech > Text to Speech
One can even select specific sub item inside a pref pane.
Here is example to select Camera under Privacy pane:
NSURL *URL = [NSURL URLWithString:#"x-apple.systempreferences:com.apple.preference.security?Privacy_Camera"];
[[NSWorkspace sharedWorkspace] openURL:URL];
Some credit goes to following site: https://macosxautomation.com/system-prefs-links.html
List of URLs for reference (*updated for macOS Big Sur & Catalina & Mojave):
Accessibility Preference Pane
Main x-apple.systempreferences:com.apple.preference.universalaccess
Display x-apple.systempreferences:com.apple.preference.universalaccess?Seeing_Display
Zoom x-apple.systempreferences:com.apple.preference.universalaccess?Seeing_Zoom
VoiceOver x-apple.systempreferences:com.apple.preference.universalaccess?Seeing_VoiceOver
Descriptions x-apple.systempreferences:com.apple.preference.universalaccess?Media_Descriptions
Captions x-apple.systempreferences:com.apple.preference.universalaccess?Captioning
Audio x-apple.systempreferences:com.apple.preference.universalaccess?Hearing
Keyboard x-apple.systempreferences:com.apple.preference.universalaccess?Keyboard
Mouse & Trackpad x-apple.systempreferences:com.apple.preference.universalaccess?Mouse
Switch Control x-apple.systempreferences:com.apple.preference.universalaccess?Switch
Dictation x-apple.systempreferences:com.apple.preference.universalaccess?SpeakableItems
Security & Privacy Preference Pane
Main x-apple.systempreferences:com.apple.preference.security
General x-apple.systempreferences:com.apple.preference.security?General
FileVault x-apple.systempreferences:com.apple.preference.security?FDE
Firewall x-apple.systempreferences:com.apple.preference.security?Firewall
Advanced x-apple.systempreferences:com.apple.preference.security?Advanced
Privacy x-apple.systempreferences:com.apple.preference.security?Privacy
Privacy-Camera x-apple.systempreferences:com.apple.preference.security?Privacy_Camera
Privacy-Microphone x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone
Privacy-Automation x-apple.systempreferences:com.apple.preference.security?Privacy_Automation
Privacy-AllFiles x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles
Privacy-Accessibility x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility
Privacy-Assistive x-apple.systempreferences:com.apple.preference.security?Privacy_Assistive
Privacy-Location Services x-apple.systempreferences:com.apple.preference.security?Privacy_LocationServices
Privacy-SystemServices x-apple.systempreferences:com.apple.preference.security?Privacy_SystemServices
Privacy-Advertising x-apple.systempreferences:com.apple.preference.security?Privacy_Advertising
Privacy-Contacts x-apple.systempreferences:com.apple.preference.security?Privacy_Contacts
Privacy-Diagnostics & Usage x-apple.systempreferences:com.apple.preference.security?Privacy_Diagnostics
Privacy-Calendars x-apple.systempreferences:com.apple.preference.security?Privacy_Calendars
Privacy-Reminders x-apple.systempreferences:com.apple.preference.security?Privacy_Reminders
Privacy-Facebook x-apple.systempreferences:com.apple.preference.security?Privacy_Facebook
Privacy-LinkedIn x-apple.systempreferences:com.apple.preference.security?Privacy_LinkedIn
Privacy-Twitter x-apple.systempreferences:com.apple.preference.security?Privacy_Twitter
Privacy-Weibo x-apple.systempreferences:com.apple.preference.security?Privacy_Weibo
Privacy-Tencent Weibo x-apple.systempreferences:com.apple.preference.security?Privacy_TencentWeibo
macOS Catalina 10.15:
Privacy-ScreenCapture x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture
Privacy-DevTools x-apple.systempreferences:com.apple.preference.security?Privacy_DevTools
Privacy-InputMonitoring x-apple.systempreferences:com.apple.preference.security?Privacy_ListenEvent
Privacy-DesktopFolder x-apple.systempreferences:com.apple.preference.security?Privacy_DesktopFolder
Privacy-DocumentsFolder x-apple.systempreferences:com.apple.preference.security?Privacy_DocumentsFolder
Privacy-DownloadsFolder x-apple.systempreferences:com.apple.preference.security?Privacy_DownloadsFolder
Privacy-NetworkVolume x-apple.systempreferences:com.apple.preference.security?Privacy_NetworkVolume
Privacy-RemovableVolume x-apple.systempreferences:com.apple.preference.security?Privacy_RemovableVolume
Privacy-SpeechRecognition x-apple.systempreferences:com.apple.preference.security?Privacy_SpeechRecognition
macOS Big Sur 10.11/10.16:
Privacy-Bluetooth x-apple.systempreferences:com.apple.preference.security?Privacy_Bluetooth
Privacy-Music x-apple.systempreferences:com.apple.preference.security?Privacy_Media
Privacy-Home x-apple.systempreferences:com.apple.preference.security?Privacy_HomeKit
macOS Monterey 12.0:
Privacy-DoNotDisturb x-apple.systempreferences:com.apple.preference.security?Privacy_Focus
macOS Ventura 13.0:
Privacy-AppBundles x-apple.systempreferences:com.apple.preference.security?Privacy_AppBundles
Privacy-ListenEvent x-apple.systempreferences:com.apple.preference.security?Privacy_ListenEvent
Dictation & Speech Preference Pane
Dictation x-apple.systempreferences:com.apple.preference.speech?Dictation
Text to Speech x-apple.systempreferences:com.apple.preference.speech?TTS
Sharing Preference Pane
Main x-apple.systempreferences:com.apple.preferences.sharing
Screen Sharing x-apple.systempreferences:com.apple.preferences.sharing?Services_ScreenSharing
File Sharing x-apple.systempreferences:com.apple.preferences.sharing?Services_PersonalFileSharing
Printer Sharing x-apple.systempreferences:com.apple.preferences.sharing?Services_PrinterSharing
Remote Login x-apple.systempreferences:com.apple.preferences.sharing?Services_RemoteLogin
Remote Management x-apple.systempreferences:com.apple.preferences.sharing?Services_ARDService
Remote Apple Events x-apple.systempreferences:com.apple.preferences.sharing?Services_RemoteAppleEvent
Internet Sharing x-apple.systempreferences:com.apple.preferences.sharing?Internet
Bluetooth Sharing x-apple.systempreferences:com.apple.preferences.sharing?Services_BluetoothSharing
Software update x-apple.systempreferences:com.apple.preferences.softwareupdate?client=softwareupdateapp
All this is possible thanks to key in Info.plist in preferencePane + CFBundleURLTypes (CFBundleURLSchemes) x-apple.systempreferences (Info.plist) in System Preferences.app
NSPrefPaneAllowsXAppleSystemPreferencesURLScheme
As of 10.15 some of the keys are located in PrivacyTCCServices.plist (Security.prefPane)
As of 10.14 Mojave some Privacy keys ceased to exists. Mojave privacy list:
Catalina privacy list:
The following is a fairly easy (and reliable) way to at least get System Preferences open to the Speech.prefPane:
- (IBAction)openSpeechPrefs:(id)sender {
[[NSWorkspace sharedWorkspace] openURL:
[NSURL fileURLWithPath:#"/System/Library/PreferencePanes/Speech.prefPane"]];
}
However, it won't necessarily be switched to the Text to Speech tab, but rather the last tab the user had selected.
It is possible to actually switch to the Text to Speech tab as well, but it's a bit more involved. You can use AppleScript to send commands to the System Preferences application, but using the ScriptingBridge.framework (See Scripting Bridge Programming Guide) is much faster.
You'll need to add the ScriptingBridge.framework to your project, and then use a command like the following in Terminal to generate a SBSystemPreferences.h header file to work with:
sdef "/Applications/System Preferences.app" | sdp -fh --basename SBSystemPreferences -o ~/Desktop/SBSystemPreferences.h
Add that SBSystemPreferences.h header to your project, then change -openSpeechPrefs: to the following:
- (IBAction)openSpeechPrefs:(id)sender {
SBSystemPreferencesApplication *systemPrefs =
[SBApplication applicationWithBundleIdentifier:#"com.apple.systempreferences"];
[systemPrefs activate];
SBElementArray *panes = [systemPrefs panes];
SBSystemPreferencesPane *speechPane = nil;
for (SBSystemPreferencesPane *pane in panes) {
if ([[pane id] isEqualToString:#"com.apple.preference.speech"]) {
speechPane = pane;
break;
}
}
[systemPrefs setCurrentPane:speechPane];
SBElementArray *anchors = [speechPane anchors];
for (SBSystemPreferencesAnchor *anchor in anchors) {
if ([anchor.name isEqualToString:#"TTS"]) {
[anchor reveal];
}
}
}
EDIT:
Sample project using the ScriptingBridge.framework method:
http://github.com/NSGod/OpenSystemPrefsTTS
For the guys who run into the same issue that I mentioned in the comment, just go to the ~/Desktop (cos I specify this position) and you'll see the SBSystemPreferences.h has been created.
However, in this header, some class declarations are missing. So you have to add this declarations explicitly.
In my case, class "item" is undefined. So add this:
#class SBSystemPreferencesItem;
Then compile it and see what's still missing, which declaration needs to be added.

Resources