ReplayKit RPBroadcastActivityViewController iPad - ipad

How do I present the RPBroadcastActivityViewController on iPads.
I am using the standard code to start a recording
RPBroadcastActivityViewController.load { [unowned self] (broadcastActivityViewController, error) in
// If an error has occurred, display an alert to the user.
if let error = error {
self.showAlert(message: error.localizedDescription)
return
}
// Present vc
if let broadcastActivityViewController = broadcastActivityViewController {
broadcastActivityViewController.delegate = self
// present
self.present(...
}
}
Works on iPhones but on iPads nothing is presented and the app kind of freezes. I have been checking out games on the app store that use this feature and I noticed the same problem.
E.g on the game Tower Dash nothing is presented when pressing the live stream button on iPads, it only works on iPhones.
I have been trying to play around with popover presentations but nothing seems to work.
Am I missing something?
UPDATE: This seems to be a bug. Even in apples own Swift Playground app this happens.
UPDATE2: Apple has actually responded to my bug report and told me that I need to present the View Controller on iPads as a popover like so
UIDevice.current.userInterfaceIdiom == .pad {
broadcastAVC.popoverPresentationController?.sourceView = view
broadcastAVC.popoverPresentationController?.sourceRect = CGRect(x: view.bounds.midX, y: view.bounds.midY, width: 0, height: 0)
broadcastAVC.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0) // no arrow
}
However it still doesnt work for me. As I mentioned this happens on apples own Swift Playground app so it must be a bug.
Fixed:
I forgot to add this line in the code mentioned above
broadcastAVC.modalPresentationStyle = .popover

You are correct that Apple's demo app does not include this little detail, but it isn't a bug. This is what I use to get it to work on an iPad. iPads require a popover to present the view and a popover needs an anchor. I chose to anchor it to the leftBarButtonItem.
if let unwrappedPreview = preview {
unwrappedPreview.previewControllerDelegate = self
if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.phone {
self.present(unwrappedPreview, animated: true, completion: nil)
}
else {
unwrappedPreview.popoverPresentationController?.barButtonItem = self.navigationItem.leftBarButtonItem!
unwrappedPreview.modalPresentationStyle = UIModalPresentationStyle.popover
unwrappedPreview.preferredContentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
self.present(unwrappedPreview, animated: true, completion: nil)
}
}

iOS 10.1 beta 2 still have the same problem.
For now, I found the only way to present a RPBroadcastActivityViewController on iPad is to present it on a trait collection's horizontal compact environment.
So you may need to tell your user switch to Split View mode before select a broadcast-supported app, then switch back to full screen. After back to full screen, you can use RPBroadcastController.startBroadcast(handler:) to start broadcast.

Related

How can I get the video from RPScreenRecorder or add a share button?

I'm recording video using RPScreenRecorder.shared().startRecording. However, I want to let the user share the video from within the app. This is the code that stops recording and previews the video in a view controller and gives the user the option to save to photos or cancel.
I cannot figure out how to grab the video from the view controllers view. When I dug into the subviews: preview.view.subviews.first!.subviews.first! There's a view of type: UIRemoteView with no subviews.
Is it possible to grab the video? Or better yet, is there a way to show a UIActivityViewController to allow the user to share the video?
for macOS I could do preview.mode = .share, but for iOS this is not available.
RPScreenRecorder.shared().stopRecording { preview, error in
guard let preview = preview else { return }
self.present(preview, animated: true, completion: nil)
}
There is a share button but it is not visible, if view controller is not presented fullscreen, I think this is a bug related to PRPreviewViewController.
You can change modalTransitionStyle and see share button.
RPScreenRecorder.shared().stopRecording { preview, error in
guard let preview = preview else { return }
preview.modalPresentationStyle = .overFullScreen
self.present(preview, animated: true, completion: nil)
}

How to add view to UIWindow so that existing view controller gets pushed up

I am dealing with no internet view and trying to achieve what Youtube ios app shows no internet view. I am able to replicate it to some extent but the problem is the no internet view is added to current UIWindow which is getting shown but as a subview. The current view controller view is not pushed up like its done in Youtube ios app . I searched in SO also about how to push it up so that UIWindow's last view becomes the no internet view.People suggested to have a controller as rootViewController and add the no internet view to it. I did the same but no internet view was shown but rest of the view controller was white. How to achieve the same mechanism like youtube one?
Below is how I am currently doing it
if netStatus == .NotReachable {
print("The internet is down.")
noInternetView.removeFromSuperview()
noInternetView = NoInternetConnection(frame : CGRect(x: 0,y: self.window!.bounds.height - 15 ,width: self.window!.bounds.width,height: 15))
noInternetView.LabelErrorMessage.text = "No Connection"
noInternetView.LabelErrorMessage.backgroundColor = UIColor.black()
let window=UIApplication.shared().windows.last
window!.addSubview(noInternetView)
internetStatus = .NotReachable
}
else {
print("The internet is working!")
noInternetView.LabelErrorMessage.backgroundColor = UIColor(netHex : "#008000")
noInternetView.LabelErrorMessage.text = "Back online"
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5) ) {
self.noInternetView.removeFromSuperview()
}
}

Different UI for iPad and iPhone

In my app I have browser and UI for iPad and iPhone should be different.
I don't use storyboards and write all programmatically.
Also, when user taps on "downloadsButton", there will be different behavior.
On iPhone a new controller with full screen size will appear from bottom, but on iPad a little square view will appear in the center of screen.
How can I do this properly ?
iPhone
iPad
Let's say you touch downloadButton to invoke downloadAction, then you may try to change the modalPresentationStyle (of the view controller you want to show) doing so:
func downloadAction() {
let downloadVc = DownloadViewController()
downloadVc.modalPresentationStyle = UIDevice.current.userInterfaceIdiom == .pad ? .formSheet : .fullScreen
self.present(downloadVc, animated: true, completion: nil)
}

MPMediaPickerController shows an empty screen on iOS10

I am trying to port my apps to iOS 10, including the visualization of a MPMediaPickerController by means of the following code:
#IBAction func handleBrowserTapped(_ sender: AnyObject){
let pickerController = MPMediaPickerController(mediaTypes: .music)
pickerController.prompt = NSLocalizedString("Add pieces to queue", comment:"");
pickerController.allowsPickingMultipleItems=true;
pickerController.delegate=MPMusicPlayerControllerSingleton.sharedController();
self.present(pickerController, animated:true, completion:{
MPMusicPlayerControllerSingleton.sharedController().storeQueue()
})
}
Yet all that appears on the screen is a full white screen with no back buttons or other, differently from the previous iOS versions. The block is called and so the picker's presentation seems to succeed. What could be the problem?
Add Key-value to Plist :
<key>NSAppleMusicUsageDescription</key>
<string>$(app Name) uses music</string>
The issue was fixed by the latest beta now asking for an authorisation to access the iTunes library.

WatchKit InterfaceController vs ViewController

Are awakeWithContext, willActivate, didDeactivate the same as viewDidLoad, viewWillAppear, viewDidAppear in terms of functionality?
I am porting code from a Swift Apple Watch tutorial that was created back when people had to add their own watch AppViewController file to test their watch apps.
The included files and things have changed with the official watch release of Xcode obviously so I’m wondering where to put where.
For example there is some code in the older AppViewController file and so I just copy/pasted it into the new InterfaceController. I put code that was in viewDidLoad, viewWillAppear, viewDidAppear into awakeWithContext, willActivate, didDeactivate respectively.
It seems the methods are different. I got 1 error saying that setText doesn’t exist:
bpmLabel.setText(currentBeatPattern.bpm) = "\(currentBeatPattern.bpm)"
…and 2 errors saying view doesn’t exist:
iconLabel.frame = self.view.bounds
self.view.insertSubview(iconLabel, atIndex: 1)
It’s like WatchKit doesn’t use some of the normal property methods or something.
Error Messages:
http://i.imgur.com/wXMdt3c.png
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
self.view.insertSubview(iconLabel, atIndex: 1) // Xcode error
}
override func willActivate() {
super.willActivate()
iconLabel.frame = self.view.bounds // Xcode error
iconLabel.textAlignment = .Center
iconLabel.font = UIFont.boldSystemFontOfSize(132)
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
newBeat()
NSTimer.scheduledTimerWithTimeInterval(8,
target: self,
selector: Selector("newBeat"),
userInfo: nil,
repeats: true)
beat()
}
func newBeat() {
// 1
if ++currentBeatPatternIndex == beatPatterns.count {
currentBeatPatternIndex = 0
}
// 2
currentBeatPattern = beatPatterns[currentBeatPatternIndex]
// 3
bpmLabel.setText(currentBeatPattern.bpm) = "\(currentBeatPattern.bpm)" // Xcode error
iconLabel.text = currentBeatPattern.icon
}
func beat() {
// 1
UIView.animateWithDuration(currentBeatPattern.duration / 2,
delay: 0.0,
options: .CurveEaseInOut,
animations: {
// 2
self.iconLabel.transform = CGAffineTransformScale(
self.iconLabel.transform, self.shrinkFactor, self.shrinkFactor)
},
completion: { _ in
// 3
UIView.animateWithDuration(self.currentBeatPattern.duration / 2,
delay: 0.0,
options: .CurveEaseInOut,
animations: {
// 4
self.iconLabel.transform = CGAffineTransformScale(
self.iconLabel.transform, self.expandFactor, self.expandFactor)
},
completion: { _ in
// 5
self.beat()
}
)
}
)
}
}
You are right that awakeWithContext, willActivate, and didDeactivate are very similar to the existing UIViewController methods like viewDidLoad, viewWillAppear, and viewDidUnload. The errors you're seeing however are related to the way WatchKit currently works. In order for a watch app to run, all the code is executed on an iPhone but the Apple Watch itself assumes responsibility for the UI elements. What that means is that any views that constitute your watch app MUST be included on your watch app's storyboard. Also, as a direct result, views cannot be instantiated and added to a parent view. All UI elements must be included in your watch app's storyboard and the watch will lay them out based on their arrangement in interface builder. This means you cannot call addSubview and you cannot set an element's frame. You can only adjust its size and set its hidden property to hide or show it on the watch. As far as this method goes –
bpmLabel.setText(currentBeatPattern.bpm) = "\(currentBeatPattern.bpm)"
You are calling the method wrong. In swift the parameters are included in the parentheses. You can call it this way if it's what you mean
bpmLabel.setText("\(currentBeatPattern.bpm)")
but setText is a method that takes a string parameter and cannot be assigned with =
As far as the animations go, I think you're out of luck. Watch apps currently are more like widgets than iOS apps and things like UIView animations and frame math are not available you. You should definitely read
up on WatchKit because there's no way you'll be able to port an iOS app directly to the watch like this.

Resources