I need to prepare an object when the user navigates to a new page in WKWebView and refresh UI. I run a WKUserScript on behalf of the user to do this.
I'm using the readystatechange event listener to detect initial page load. I'm also listening to the visibilitychange event to refresh UI if the DOM is already loaded on a "Go back" or "Go Forward" action.
document.addEventListener('visibilitychange', () => {
//do whatever if the DOM is already loaded and if we are visible.
});
document.addEventListener('readystatechange', (event) =>
{
//do whatever when page is loaded
});
On certain websites however I noticed that neither of these events are being fired when I navigate -goForward: and -goBack:
I'm not sure why. My WKUserScript is in WKContentWorld.defaultClientWorld so it shouldn't be interfering with the javascript of the page. Is there another JS event I'm missing?
I could pick up the changed URL on the native code side but it would be nice to keep this all contained within the WKUserScript as this UI is for the "webview" and the native code shouldn't have to be bothered with having to patch in the additional glue. Is there another DOM event I need to listen to? I tried listening to window's pageshow but that didn't work. Also experimented a bit with the window's popstate event but no luck.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
It appears a lot of useful WWDC session videos from previous years have been scrubbed from the developer.apple.com? I cannot find the WWDC session "Customized Loading in WKWebView" from 2017 in the Developer app nor on the developer website.
There are lots of other videos that would be useful to watch, even from years ago. Am I just not looking in the right place?
I'm having a hard time finding samples that clearly explain how to use WKContentRuleList objects. I read that WKContentRuleList use the same format as Safari content blocker extensions however when I try to compile a content blocker from the sample app AdoptingDeclarativeContentBlockingInSafariWebExtensions it complains about missing a "trigger". I get
Error Domain=WKErrorDomain Code=6 "(null)" UserInfo={NSHelpAnchor=Rule list compilation failed: Invalid trigger object.}
When I try to use the rules from the AdoptingDeclarativeContentBlockingInSafariWebExtensions sample project:
[
{
"id": 1,
"priority": 1,
"action": { "type": "block" },
"condition": {"regexFilter": ".*", "resourceTypes": [ "image" ] }
},
{
"id": 2,
"priority": 1,
"action": { "type": "allow" },
"condition": {"regexFilter": "wikipedia", "resourceTypes": [ "image" ] }
}
]
So if WKContentRuleList requires different keys/value pairs than Safari content blockers are those differences documented anywhere? I can't really find any good info on this.
Thanks in advance.
Is there a way to block certain embedded inline javascript elements using WKContentRuleList? For example
<script>
evilJavascriptHere
</script>
The documentation states that you can specify a url-filter but what about inline scripts?
I have a custom pop animation is use with UINavigationController. I provide this via the delegate method
-
-(nullable id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController*)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController*)fromVC
toViewController:(UIViewController*)toVC
And it works except when I push the view controller initially from UISearchController's .searchResultsController. This issue is that when I push on the navigation stack when the UISearchResultsController is displaying the searchResultsController, when I pop back the UIViewControllerContextTransitioning passed to my animator doesn't provide values to account for the search controller displayed over the main view controller and the custom animation doesn't work.
Is there a good way to handle this? Thanks in advance.
So I'm using a custom presentation controller which requires me to specify a transitioningDelegate on the view controller before presenting it like this:
vcToPresent.modalPresentationStyle = UIModalPresentationCustom;
vcToPresent.transitioningDelegate = transitionDelegate;
Now I want to enforce a particular view controller to always use my custom presentation controller. Unfortunately I cannot just override the presentationController getter and return my own custom class; I have to make a transitioning delegate and an additional animator (and my custom presentation controller can animate alongside it). To have a view controller use my own presentation controller I have to do this:
-(void)presentCustomVC
{
MyViewController *vcToPresent = [MyViewController makeViewController];
MyTransitioningDelegate *transitionDelegate = [[MyTransitioningDelegate alloc]init];
vcToPresent.modalPresentationStyle = UIModalPresentationCustom;
vcToPresent.transitioningDelegate = transitionDelegate;
[self presentViewController:vcToPresent animated:YES completion:nil];
}
So I have to copy this transitioningDelegate set up code in every view controller that presents MyViewController. I can make the API look a little better by creating a factory method in MyViewController like this:
+(MyViewController*)makeViewController
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
MyViewController *theVC = [storyboard instantiateInitialViewController];
MyTransitioningDelegate *transDelegate = [[MyTransitioningDelegate alloc]init];
theVC.modalPresentationStyle = UIModalPresentationCustom;
theVC.transitioningDelegate = transDelegate;
return theVC;
}
The problem with that is the transitioningDelegate gets deallocated right away (before the view controller can be presented). The transitioningDelegate property on UIViewController is weak for some reason.
Shouldn't the transitioningDelegate property be declared strong? My custom transitioningDelegate has no strong reference to the presented view controller? If I add a redundant property to MyViewController like this:
@property (nonatomic,strong) MyTransitioningDelegate *strongTransDelegate;
And then do this:
theVC.modalPresentationStyle = UIModalPresentationCustom;
theVC.transitioningDelegate = transDelegate;
theVC.strongTransDelegate = transitionDelegate;
All seems to work well. When the view controller is dismissed the transitioning delegate is deallocated. However I'm assuming the transitioningDelegate property on UIViewController was declared as weak for a reason? I don't want to accidentally create a retain cycle in some unforeseen circumstance. Documentation makes no mention on who should be the "owner" of the transitioning delegate?
I'm using a custom UIPresentationController. I'd like the replicate the behavior of UISheetPresentationController and allow user interaction the presenting view controller when the presented view controller does not cover the entire screen.
I tried this:
-(void)presentationTransitionDidEnd:(BOOL)completed
{
UIView *theView = self.presentingViewController.view;
theView.userInteractionEnabled = YES;
}
But has no effect. Is it possible to achieve this behavior? Thanks in advance
I’m using UISheetPresentationController with a UIViewController.
While the sheet is being resized I’d like to position certain subviews a certain way during the resizing event. For example I may hide some subviews on a smaller detent and unhide them on a larger detent. But while the sheet is being resized in between the small and large detent I’d like to have some subviews placed at certain locations of the view hierarchy.
As far as I can tell the only way to do this is with unreliable hard coded values:
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
CGFloat currentHeight = self.view.bounds.size.height;
if (currentHeight <= mediumDetent)
{
[self doLayoutForMediumDetent];
}
else if (currentHeight >= fullSizeDetent)
{
[self doLayoutForFullSizedDetent];
}
else
{
[self doLayoutInBetweenFullAndMediumSheetWithCurrentSize:currentHeight];
}
}
I don't really know for sure the height of the detents. I'm using estimates so this layout code is fragile. For the medium detent the documentation states that it is "A system detent for a sheet that is approximately half the height of the screen, and is inactive in compact height." but on certain devices the medium detent height is not exactly 1/2 the screen height.
Ideally it would be nice to have API like this:
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
CGFloat mediumHeight = [self.sheetPresentationController resolvedHeightForDetentWithIdentiier:someID withTraitCollection:self.traitCollection];
CGFloat fullHeight = [self.sheetPresentationController resolvedHeightForDetentWithIdentiier:FullSizeID withTraitCollection:self.traitCollection];
if (self.sheetPresentationController.isInLiveResize)
{
//do whatever during live resize
}
else
{
//do whatever at the current size
}
}
Is there currently a better way to achieve what I'm after?
Edit: Was able to resolve. This thread may be deleted.
I'd like to ensure certain content doesn't overlap UISheetPresentationController's grabber.
In the view controller subclass that is being presented as a sheet via UISheetPresentationController I tried inspecting self.view.safeAreaInset.top hoping that this would account for the UISheetPresentationController's grabber but safeAreaInset.top is 0 unfortunately.
Right now I'm just using a hard coded value but is there API for this I overlooked?
I'm trying to configure the "Now Playing" information for my app on iOS. Using MPNowPlayingInfoCenter/MPRemoteCommandCenter is pretty straightforward for this. The issue I'm having is that the audio I'm playing is generated "on the fly" and I do not know the exact duration in seconds.
I am able to synthesize an NSProgress to display the progress of the playback but the units are not in seconds. So if I use the NSProgress units with MPNowPlayingInfoCenter the "Now Playing" shows the units in seconds but it appears to be jumpy (because again my progress units are not in seconds but an approximation of the percent completed).
[playInfo setObject:@(self.progress.totalUnitCount) forKey:MPMediaItemPropertyPlaybackDuration];
[playInfo setObject:@(self.progress.completedUnitCount) forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
I see there is a MPNowPlayingInfoPropertyPlaybackProgress which looks like it would be perfect. I tried setting that instead of MPMediaItemPropertyPlaybackDuration/MPNowPlayingInfoPropertyElapsedPlaybackTime but it appears to have no effect in the "Now Playing" UI. I also tried setting MPNowPlayingInfoPropertyIsLiveStream to YES but that just makes the "Now Playing" UI display "Live" instead of the progress value. Is there a way I can show a progress bar without the units being displayed in seconds?
Thanks in advance.
Uploading an App Preview Video for a Mac App Fails with Error "Your app preview contains unsupported or corrupted audio" even though the video contains no audio.
Anyone run into this and know of a workaround?
I filed FB12151982
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
App Store Connect
App Submission
When I use the verify receipt endpoint in my Mac apps, the Mac App Store review team always rejects them. I have apps that have been on the store for years that used this code and they verify in the production environment fine but every time I try to send an update it gets rejected.
My app does simple receipt validation like this:
My app uses the verify receipt endpoint and talks to the server directly (not super secure but that’s okay I don’t need to maintain a server for this app).
The verify receipt endpoint always says the receipt is invalid in in the App Review team’s testing environment.
My app calls exit(173) after the verify receipt endpoint tells me the receipt is invalid.
The systems shows a dialog saying the app is Damaged.
I cannot reproduce this in my testing environment nor do I see the issue occurring in the current versions of these apps live on the App Store (no code changes has been made to the receipt validation code). The issue seems to only occur in the App Review team’s testing environment.
I've been running into this issue for about a year now. I had a TSI opened last year related to this but the issue never got resolved. I just have to comment out the receipt validation code in every app...then submit my update.
Anyone else run into this with verify receipt?
I have a multiple window Mac Catalyst app. I'm using a NSToolbar and the menu bar via UIMenuBuilder.
I noticed after changing windows the menu bar isn't always validating properly. For example my app implements "Undo" and "redo". So I can reproduce the issue using these steps:
Perform an action that can be undone.
Open a new window. This new window has its own undo manager.
In the Menu bar select Edit -> Undo
Undo validates even though the current window has nothing on its local undo stack. If invoked undo is performed on the inactive window which definitely seems wrong.
The same thing sometimes happens in reverse (that is, undo doesn't validate when it should after switching windows). This also happens with other actions after switching windows.
Sometimes I can get the actions to validate by hitting the Tab key to move focus then shift tabbing back, which seems to force proper lookup in the responder chain (but sometimes that doesn't work).
It seems that Catalyst is losing track of the real active window/window scene for some reason and is validating actions on the wrong window scene.
Anyone experience this and know where I could be going wrong and/or know of a possible workaround?
I tried subclassing UIApplication and implementing the methods there (and then forwarding them to the active UIWindowScene). However this doesn't work, the wrong window scene has its activationState set to UISceneActivationStateForegroundActive when the problem occurs.
I'm trying to create a dynamic menu on Mac Catalyst. Using a UIBarButtonitem like so to make a "pull down" button:
UIDeferredMenuElement *deferredmenuElement;
deferredmenuElement = [UIDeferredMenuElement elementWithUncachedProvider:^(void (^ _Nonnull completion)(NSArray<UIMenuElement *> * _Nonnull))
{
UIAction *actionOne = [UIAction actionWithTitle:@"Action One" image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
NSLog(@"action one fired.");
}];
UIAction *actionTwo = [UIAction actionWithTitle:@"Action Two" image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
NSLog(@"action two fired.");
}];
UIAction *actionThree = [UIAction actionWithTitle:@"Action Three" image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
NSLog(@"action three fired.");
}];
completion(@[actionOne,actionTwo,actionThree]);
}];
UIMenu *wrappedMenu = [UIMenu menuWithChildren:@[deferredmenuElement]];
UIBarButtonItem *uiBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:nil
menu:wrappedMenu];
uiBarButtonItem.image = [UIImage systemImageNamed:@"rectangle.and.pencil.and.ellipsis"];
self.navigationItem.rightBarButtonItems = @[uiBarButtonItem];
The button appears in the toolbar but when I click it to expose the menu I get a menu with on element in it that says "Loading...". The the uncached provider block is never called.
Running Ventura 13.2.1 and Xcode 14.2.