Use ReplayKit to record any app on screen - ios

I am trying to create an iPhone app that records not only the app's screen but if put into the background it records everything on the screen, including other apps. This is how recording from "Control Center" works. The difference is I want to get access to the video immediately without user intervention, with the user's consent of course.
I've implemented code using ReplayKit2 on iOS 12 that uses an embedded Broadcast Upload Extension. I have not found any examples online that work like this.
I posted the code on Bitbucket: https://bitbucket.org/breelig/replaykitbroadcasttofile/src/master/
The closet similar question I found on SO is: ReplayKit stops screen recording in background mode of the application or outside the app?
Update
Based on the good responses by #KaneCheshire and #AndreyA. below and other random sources I was able to develop a solution that works. Please see the code in my BitBucket link above.

From the docs:
Apps on a user’s device can share the recording function, with each
app having its own instance of RPScreenRecorder. Your app can record
the audio and video inside of the app, along with user commentary
through the microphone
The only other way to record the screen is through a Broadcast Upload Extension, which requires the user to initiate it through Control Centre.

I've faced almost the same problem that you did and it's absolutely lacking any kind of guides or documentation.
The way I resolved this problem to myself is setting nil to my preferred extensions, so it makes RPSystemBroadcastPickerView to show all of them including system screen video capture:
override func viewDidLoad() {
super.viewDidLoad()
let broadcastPicker = RPSystemBroadcastPickerView(frame: CGRect(x: 100, y: 100, width: 80, height: 80))
broadcastPicker.preferredExtension = nil
view.addSubview(broadcastPicker)
}
Also I've found one thing that I've figured out to be useful - this Twilio lib and its example - https://github.com/twilio/video-quickstart-swift/tree/master/ReplayKitExample - These guys have made a decent work in area of video/audio capturing and we can try to use their experience.

You can find your exactly preferedExtension here:
When you add pickerView.preferredExtension exactly the Bundle Identifier, your app will be showed on the Recording App List. Hope this helps!

Related

Are iOS app clips launchable from an url?

Are iOS app clips launchable from an URL?
The Apple description says that the QR code embeds an encrypted URL to access the clips. Is it possible to use directly that link like with deep links?
As I understand, URLs can only be opened from Safari Smart App Banner. I managed to do that. Apple states in their forums that it is also possible from QR codes.
Looks like you can't just click a link - like in Universal Link - and the App Clip Card will show up.
If I understood correctly, you can set up invocation URLs in App Store Connect and when the system opens a registered URL your App Clip should launch.
You can learn more in this WWDC session and from the documentation.
When a user shares a link to a site that displays a smart banner configured for AppClip, then only message will present a banner that will invoke an App Clip.

Posting to correct Instagram Account with UIActivityViewController

I am using UIActivityViewController to post images to Instagram app from MY app.
Please note my app does not use Instagram API or log in to users' Instagram Account.
let sharingImage = button.backgroundImage(for: [])
let avc = UIActivityViewController(activityItems: [sharingImage as AnyObject], applicationActivities: nil)
avc.excludedActivityTypes = [.addToReadingList,.airDrop,.assignToContact,.copyToPasteboard,.openInIBooks,.postToFacebook,.postToFlickr,.postToTencentWeibo,.postToTwitter,.postToVimeo,.postToWeibo,.saveToCameraRoll,.message,.mail,.print]
if let wPPC = avc.popoverPresentationController {
wPPC.sourceView = followUsButton
}
self.present(avc, animated: true, completion: nil)
I am logged into my Instagram App with multiple accounts. Upon share from MY app, Instagram tries to post to the account 'A' which is currently logged in (inside the Instagram app). This makes sense.
However, if I now switch to the Instagram app and switch to account 'B' inside it, go back to MY app and then try to share again, it continues to try to post to Account 'A'.
The only way to fix it, is to kill MY app and start it again and then it loads the correct currently logged in account 'B'.
Is there a way to programmatically reload the correct Insta account while sharing?
This is only a workaround however might be your only choice at the moment as you see that even native Photos has the same issue so it is rather down to Apple to fix it.
In your application's Info.plist, add a boolean key UIApplicationExitsOnSuspend with the value YES. See the Information Property List Key Reference for more information.
This way the app is getting terminated when enters a background state and once you go back to it it will get reloaded. The user might not notice the difference.
Perhaps before killing the app you could add some interface state saving function in:
optional func applicationWillTerminate(_ application: UIApplication)
I don't know how your app is laid out but you could create a singleton class which could be implementing Codable and keep tracking all the app state variables which would have a save and load function. Saving would be triggered upon termination and loading when app is launching.
I hope it will help in some way.
EDIT1: Should work in iOS 13
Below this code should work and terminate your app however it is not recommended and you might face an issue when uploading to AppStore. I guess you can challenge the rejection with the Apple review team by explaining that they have a bug in the SDK and point them to the problem.
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
exit(0)
}
}
Short answer, I doubt.
UIActivityViewController doesn't give you control over the user's login status (which is why it's interesting to use). IMO, that's a bug on Apple side. So, unless there's a secret way to clear the authorisation tokens that the iOS runtime has stored within your app memory, I don't see how you could possibly achieve what you want.
Plus, if Photos app has the same behaviour, that's not a good sign...
Just in case, when you say that the problem occurs when switching accounts, do you mean
In MY app, you immediately try to post from the same ViewController?
You move to a parent View (hence destroying the old one)back , then to the same view as 1/?
Do you have the same result in both case? I am asking because when instantiating a new UIActivityViewController in a new view, the runtime might fetch the new user login profile, while if you instantiate it from the same view that was used to post from the old account, it might not do so (hence it'll use the old login)
This is iOS issue not specific to your app.

How to disable "turn-to-sleep" on Apple Watch?

I'm working for an airline with their app. We have released the app on Apple Watch, but have a big problem: the scanners for the QR-code used to go through security and to board the plane, are scanning from the bottom and up...
This means that you cannot use the watch app, because when you turn your wrist, the watch goes in black sleep mode.
Is there any way of turning this temporarily off for a view? I have heard rumours that it can be disabled in WatchOS 4, but can't find out how.
Thanks for the help! :)
This is very interesting question. There seems no way to present this without the PassKit(Or even with passkit the screen will still go off...) I think PassKit Controller has some functions when you focus the QR code it doesn't go to sleep...
reading the watchkit reference in here , you need to implement presentation of the passkitController.
Because right now you cannot tell apple watch to resign sleep, it is agains human guidelines + it would really be energy-consuming solution. Instead, apple handles for you with PassKitController instance. So on watchkit, you do this:
let pass = PKPass(data: /*There goes your data*/, error: nil)
presentAddPassesController(withPasses: [pass]) {
// Do smth on completion
}
You definitely should try to inform user and give him access to export the pkpass to wallet...
Resources used:
https://github.com/TwoRingSoft/pkpassgenerator
For generating custom passkit object
This could help you as well:
https://www.natashatherobot.com/url-apple-wallet-passkit-pass/?utm_campaign=This%2BWeek%2Bin%2BSwift&utm_medium=email&utm_source=This_Week_in_Swift_138

iOS App Metadata Rejected? Anything to Check in ViewDidLoad?

So I just got an app's metadata rejected. Their message:
Your iTunes Connect settings indicate that your app serves third-party advertisements. However, we were unable to locate ads in your app.
Please reply to this message to provide the steps for locating third-party ads in your app. When we hear back from you, we will continue the review.
But my app presents a google adBanner as soon as they game is launched. Even if you somehow press the start button before the Ad is loaded, it still presents itself during the game...
Is there any reason they wouldn't see the AdBanner?
I have my own adUnitID and it displays an Ad on my iPhone 6+ device and also the 4S simulator...
Also, I ticked the "servers advertisements within app" check box before submitting:
I've replied saying:
Hello.
Please see screenshot of a Google AdBanner... It should show upon launch of the game.
Steps:
-Open App
-An Ad should load within seconds.
Please advise. Thanks.
and attached a screenshot, showing it...
I've done it the same way I have in my last app which is live and serving ads.
This is how I load and serve the ad in the gameViewController:
override func viewDidLoad() {
super.viewDidLoad()
googleBannerView = GADBannerView(adSize: kGADAdSizeSmartBannerPortrait)
googleBannerView.adUnitID = "ca-app-pub-blahblahblah/1010101"
googleBannerView.rootViewController = self
let request: GADRequest = GADRequest()
googleBannerView.loadRequest(request)
googleBannerView.frame = CGRectMake(0, view.bounds.height -googleBannerView.frame.size.height, googleBannerView.frame.size.width, googleBannerView.frame.size.height)
self.view.addSubview(googleBannerView!)
//more stuff
}
Is there anything else I can do to check in the code that it's definitely serving ads? I can't see anything wrong with it.
I can't think of any reason it wouldn't be serving their end...
Also, if it's still in review, do I have to wait another week?
Metadata rejected in itunesconnect means 1) that something wrong with app metadata (description, screenshots, etc.) or 2) Something wrong with things that are serving your app (backend, some authorization, etc.). Also it means that you can resubmit your app without uploading new app binary file. Seems like the second case is yours, and the app review team thinks that something went wrong with you ad serving or ad banner in the place that they couldn't find.
I recently got this rejection when they couldn't find my third party ad, Admob, in my app. This was because I was using admob just for interstitial and I used iAd for banners. I had to tell them how and where to get those admob ads to show.
you can try googleBannerView.hidden = false (this is the default value) and see if there's a difference
But for your case, since you're using admob banners that should have shown in the first place and you were able to make it show on your test, the only reason I could think of why they did not find it is because of no ad inventory from Admob (I stated this reason as well when I replied) which is rare but still happens.
It will stay in review/rejected state until you fix it by uploading a new binary and resubmitting (which would take the normal week submission and reviewing) or when they are convinced that there is a third party ad network used (from replying and stating your case) which they'll change the app status to 'ready for sale' or approved. Mine took 2 days I think.

Stream to VLC for iOS via URL Scheme

I'm trying to link to the iOS VLC app via its URL scheme. I need to open a FLV file(preferably as a stream, rather than downloading). I have tried vlc://http://domain.com/path/to/video.flv which opens VLC with a popup asking if I would like to play or download. Tapping download works, however play doesn't do anything except close the popup(I can get it to eventually work if I tap Play in the popup -> Play in Control Centre -> tap back in VLC). Is there a way to get it to play by directly through the URL?
Bonus points if you figure out how to select the "Scan for Subtitles" option in the "Open Network Stream" section of VLC. ;)
I've looked all over Google and can't find any documentation of the URL scheme. Any help is greatly appreciated.
the vlc:// pseudo protocol is broken in the current 2.6.4 release - it is fixed in 2.6.5 which is currently waiting for review by Apple. I hope that it will be out this week but this is beyond our control.
Generally speaking, I recommend to use another protocol though based on x-callback-url, documented on our wiki: https://wiki.videolan.org/Documentation:IOS/#x-callback-url
Regarding an extra subtitles URL, this is currently not supported. We could add it though, it's just that nobody asked for it so far.
For those who want to add subtitle it has been added in this commit and can be used like this:
vlc-x-callback://x-callback-url/stream?url=http://example.com/dogs.mp4&sub=https://example.com/dogs.srt

Resources