OSX 10.10 WKWebView set UserAgent (Swift) - macos

i tried to set a Custom UserAgent for the WKWebView in my Mac App. Unfortunately the specified Custom String never gets set. With the iOS SDK it's not a big deal
NSUserDefaults.standardUserDefaults().registerDefaults(["UserAgent" : "Custom Agent"])
But with the Mac SDK it does not work. I also tried
let url = NSURL(string: startURL)
let req = NSMutableURLRequest(URL: url!)
req.setValue("Custom Agent/1.0", forHTTPHeaderField: "User-Agent")
webView!.loadRequest(req)
Thanky you for every help.

You have to expose some private methods of WKWebView in your ObjC bridging header and call them to change the UA.
Adapted snippets from my mini-browser app:
bridging-header.h
// https://github.com/WebKit/webkit/blob/master/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h
#import WebKit;
#interface WKWebView (Privates)
#property (copy, setter=_setCustomUserAgent:) NSString *_customUserAgent;
#property (copy, setter=_setApplicationNameForUserAgent:) NSString *_applicationNameForUserAgent;
#property (nonatomic, readonly) NSString *_userAgent;
#end
macpin.swift
if let agent = withAgent? {
webview._customUserAgent = agent // specify full UA
} else {
webview._applicationNameForUserAgent = "Version/8.0.2 Safari/600.2.5"
// appended to UA, mimicing Safari
}
webview.loadRequest(NSURLRequest(URL: url))

Now, in Swift 2, you can do it without Obj-C with help of new selector API.
Like this:
let webView = WKWebView()
webView.performSelector("_setApplicationNameForUserAgent:", withObject: "My App User Agent addition")
But avoid to use it in production code in this form. Try to hide it somehow :)

Related

macOS RTCMTLNSVideoView video content mode

I'm trying to make RTCMTLNSVideoView available in webrtc for mac to fill the entire container view (videoContainerView is the container NSView, rtcTrack is RTCVideoTrack)
let videoView = RTCMTLNSVideoView(frame: .zero)
videoView.frame = videoContainerView.bounds
videoView.makeBackingLayer()
videoView.layer = CAMetalLayer()
videoView.wantsLayer = true
videoView.layer?.backgroundColor = NSColor.red.cgColor
videoView.layer?.contentsGravity = .resizeAspectFill
rtcTrack?.add(videoView)
videoContainerView.addSubview(videoView)
It results with video being fit only using one size (aspectFit). I can't seem to make it fill the entire container. iOS webrtc has a property videoContentMode. On mac it's missing. How to control the video content mode in this case on mac webrtc? Any ideas appreciated.
Thanks
Easy fix:
if let metalView = videoView.subviews.first(where: { view in view is MTKView }) {
metalView.layerContentsPlacement = .scaleProportionallyToFill
}
Old answer:
As I said in the comments, you have to access private property metalView.
To do this, create file named RTCMTLNSVideoView+Private.h in your project with the following code
#import <MetalKit/MetalKit.h>
#import "WebRTC/RTCMTLNSVideoView.h"
#interface RTCMTLNSVideoView ()
#property(nonatomic, strong) MTKView *metalView;
#end
And then you can reassign content mode:
videoView.metalView.layerContentsPlacement = .scaleProportionallyToFill

How get an item in control center of Touch Bar on the right?

The app TouchSwitcher add item beside lightscreen and volume items :
https://hazeover.com/touchswitcher.html
Is there a solution to display an item into the control strip on the right region of touch bar ?
I can't find any help in official documentation about it...
Please help me !
After decompiling, I discovered some APIs in a framework called DFRFoundation located under /System/Library/PrivateFrameworks, and a related method DFRElementSetControlStripPresenceForIdentifier. I find it quite difficult to get further, so I answer here only to let you know that the API for this is in a private framework. Hope someone would reveal the secrets someday.
Here's what I use. Pass an NSView and an identifier of your choice to the controlStrippify() function. My attempts at doing the exact same thing using Swift have resulted in crashes, ports welcome :). Inspiration from https://github.com/a2/touch-baer.
#import Cocoa;
#import Foundation;
// See: https://github.com/a2/touch-baer
extern void DFRElementSetControlStripPresenceForIdentifier(NSString *string, BOOL enabled);
#interface NSTouchBarItem ()
+ (void)addSystemTrayItem:(NSTouchBarItem *)item;
#end
#interface NSTouchBar ()
+ (void)presentSystemModalFunctionBar:(NSTouchBar *)touchBar systemTrayItemIdentifier:(NSString *)identifier;
#end
void controlStrippify(NSView *view, NSString *identifier) {
if (#available(macOS 10.12.2, *)) {
NSCustomTouchBarItem *touchBarItem = [[NSCustomTouchBarItem alloc] initWithIdentifier:identifier];
touchBarItem.view = view;
[NSTouchBarItem addSystemTrayItem:touchBarItem];
DFRElementSetControlStripPresenceForIdentifier(identifier, YES);
} else {
// Fail!
}
}

Transparent background WKWebView (NSView)

I am building a Mac application using Swift. Therefor, I want to make a WKWebView transparent, so it shows the text of the loaded HTML, but the background of my underlaying NSWindow is visible.
I tried
webView.layer?.backgroundColor = NSColor.clearColor().CGColor;
which hadn't any effect. WKWebView inherits from NSView, but I don't know if this helps.
Another solution would be to insert a NSVisualEffectView as the background of the WebView, but I don't know how to accomplish that, either!
Use this in macOS 10.12 and higher:
webView.setValue(false, forKey: "drawsBackground")
It was not supported, then they fixed it:
https://bugs.webkit.org/show_bug.cgi?id=134779
The way to make it transparent is to:
myWebView.opaque = false
Code below works for me perfectly, also color is set to clearColor by default.
[wkWebView setValue:YES forKey:#"drawsTransparentBackground"];
I used this for macOS 10.12. without problems in OjbC:
[self.webView setValue:#YES forKey:#"drawsTransparentBackground"];
Under macOS 10.13.+ I got the following console warning message:
-[WKWebView _setDrawsTransparentBackground:] is deprecated and should not be used
The ONLY working solution was:
[self.webView setValue:#(NO) forKey:#"drawsBackground"];
I tried the below in many scenarios and it didn't work:
give the webView and the enclosingScrollView a layer and edit it's properties (backgroundColor, isOpaque)
give the webView and the enclosingScrollView a clear background color
inject javascript without the setValue forKey: in the webview.
Additionally I did use:
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
if (self.isWebviewsBackgroundTransparent) {
[self insertTransparentBackgroundTo:webView];
}
}
- (void)insertTransparentBackgroundTo:(WKWebView *)webView
{
NSString *transparentBackgroundJSSString = #"document.body.style = document.body.style.cssText + \";background: transparent !important;\";";
[webView evaluateJavaScript:transparentBackgroundJSSString completionHandler:nil];
}
Updated, slightly better solution (2022). There is a private property drawsBackground on WKWebViewConfiguration. This property has been introduced in macOS 10.14 so it won't go away.
//https://opensource.apple.com/source/WebKit2/WebKit2-7610.2.11.51.8/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h.auto.html
//One can verify that the property still exists:
//https://github.com/WebKit/WebKit/blob/main/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h
#property (nonatomic, setter=_setDrawsBackground:) BOOL _drawsBackground WK_API_AVAILABLE(macos(10.14), ios(12.0));
Example:
let configuration = WKWebViewConfiguration()
var requiresDrawBackgroundFallback = false
if #available(OSX 10.14, *) {
configuration.setValue(false, forKey: "sward".reversed() + "background".capitalized) //drawsBackground KVC hack; works but private
} else {
requiresDrawBackgroundFallback = true
}
let webView = WKWebView(frame: .zero, configuration: configuration)
if requiresDrawBackgroundFallback {
webView.setValue(false, forKey: "sward".reversed() + "background".capitalized) //drawsBackground KVC hack; works but private
}

Xcode segue with data to set label

Hello guy's and girl's,
I got a question, i'm new to objective c and iphone apps. But i'm trying to make a few simple applications but i have trouble with creating a segue that also sets the label in the next view controller.
The situation is as following. i have a Tableviewcontroller with an loaded nsarray of data.
Next i have created a segue (ctrl + drag). Al works so far.
Now the viewcontroller has an label, i have namend the segue and a'm trying the following code.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowTitleInOtherViewController"]) {
PracticeViewController *pvc = [segue destinationViewController];
pvc.labelForDisplayData.text = #"Segue complete";
pvc.labelForDisplayData.textColor = [UIColor blueColor];
pvc.labelForDisplayData.font = [UIFont boldSystemFontOfSize:50];
}
}
i have imported the header and the viewcontroller header looks like the following:
#interface PracticeViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *labelForDisplayData;
#end
Please tell me what i am doing wrong. (there are no error's)
Recommendation
From your description (as long as you've connected the outlet in your storyboard) then this workflow should be okay. You are not showing how the segue is initialized (i.e., performSegueWithIdentifier). Please see this stack overflow question for more details (link). I've posted a few tips on manual segueing. If you've resolved this issue please update your original question. Here is another sample of calling a manual segue (link). Please advise if this issue is still open or share the problem/solution.
New Apple Tutorial on Storyboards
Hope this helps.
Make the Label property to strong instead of weak
#interface PracticeViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *labelForDisplayData;
#end

Adding a sound to load with a spash screen in xcode

I have set up a splash screen for my app project and would like to have an sound (mp3) play just after the splash screen loads. I am new to using xcode and wondered whether some one could advise on what code I will need to input/where to input it..
Many Thanks
You implement a yourintrosound.wav system sound in the first view controller, then play it with the appDelegate just after the view controller is loaded:
in your firstViewController.h
#interface...
CFURLRef yourSound;
SystemSoundID soundFileObject;
#property (readwrite) CFURLRef yourSound;
#property SystemSoundID soundFileObject;
in your firstViewController.m viewDidLoad
NSURL *rightSound = [[NSBundle mainBundle] URLForResource: #"yourintrosound" withExtension: #"wav"];
self.yourSound = (CFURLRef) [rightSound retain];
AudioServicesCreateSystemSoundID (yourSound, &soundFileObject);
[rightSound release];
in your AppDelegate.m application: didFinishLaunchingWithOptions:
(just after [window makeKeyAndVisible] or any splash screen display you implemented)
AudioServicesPlaySystemSound (firstViewController.soundFileObject);
and do dot forget the AudioToolbox framework!

Resources