How to detect AVplayer and get url of current video from WKWebView?
Asked Answered
E

6

15

I'm using below code to extract url from UIWebView: it is working fine but, this same code using for WKWebView it's not working anymore. Can anyone help me? The video playing in WKWebView is Inlineplacyback not in fullscreen.

My code is :

 NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemBecameCurrent(_:)), name: NSNotification.Name("AVPlayerItemBecameCurrentNotification"), object: nil)

 @objc func playerItemBecameCurrent(_ sender : NSNotification){
    let playerItem: AVPlayerItem? = sender.object as? AVPlayerItem
    if playerItem == nil {
        print("player item nil")
        return
    }
    // Break down the AVPlayerItem to get to the path
    let asset = playerItem?.asset as? AVURLAsset
    let url: URL? = asset?.url
    let path = url?.absoluteString

    print(path!,"video url")
}

Response URL :

https://r2---sn-po4g5uxa-5hql.googlevideo.com/videoplayback?txp=5531432&sparams=clen%2Cdur%2Cei%2Cgir%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cpcm2%2Cpl%2Cratebypass%2Crequiressl%2Csource%2Cexpire&ip=103.37.181.55&ratebypass=yes&id=o-AM9UWIaxopyYZX4gikGuswG8EMi3dhH_PPBMIqY5cbXj&expire=1554400796&c=MWEB&fvip=4&initcwndbps=481250&ipbits=0&mime=video%2Fmp4&dur=60.093&lmt=1554142002789460&key=yt6&mt=1554379078&itag=18&source=youtube&gir=yes&requiressl=yes&signature=6C68366FC249958BB8E95A5D88074FF8BCB99745.DA113E66DD0B46863BAE52DAA3CAB31FD141F0E5&clen=2708520&mm=31%2C29&mn=sn-po4g5uxa-5hql%2Csn-cvh7knek&ei=vPGlXPOWHIWD8QOO1KBo&ms=au%2Crdu&pcm2=no&pl=24&mv=m&cpn=I9d32bNmeq3kf0jn&cver=2.20190403&ptk=youtube_none&pltype=contentugc

It's video URL not Webpage URL so, please help me how to get this. Thanks.

Eudemon answered 27/3, 2019 at 12:52 Comment(11)
Can you provide the url you are using?Arbitrator
no I'm using WKWebView, so when webview detect playing video i wan't to get it. can you help me ?Eudemon
Check this: #29087716Europeanize
@ViraniVivek is a user able to navigate inside WebView to different pages that do not contain videos? or only video links?Bacillary
@Bacillary user able to navigate any different page inside webview it contains video or not but when going to page which contains video and if video play than get the url of current video playing.Eudemon
@viraniVivek this Link might help you to decode above URL tyrrrz.me/Blog/Reverse-engineering-YouTubeMontymonument
if URL contains two signature """signature = s[25] + s.substring(3,25) + s[0] + s.substring(26,42) + s[79] + s.substring(43,79) + s[91] + s.substring(80,83); """ <- this js will be helpful @viraniVivekMontymonument
@Montymonument no i'm not go with only youtube, i go with all sites which contain videos so ,please give me any general answer or detect video from webview you can see this application from itunes itunes.apple.com/us/app/dmanager-browser-documents/…Eudemon
Please are you find the solution to get url of current video from WKWebView?Labbe
@HamzaAlmass i'm still searching but no solution for this.Eudemon
@ViraniVivek thank you i'm also searching and no solution for thisLabbe
B
11

This is kind of a hack, but the only way I found to accomplish this.

First set yourself as WKWebView navigation delegate:

self.webView?.navigationDelegate = self

Now listen to all navigation changes, and save the requested url:

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if let urlStr = navigationAction.request.url?.absoluteString {
            //Save presented URL
            //Full path can be accessed via self.webview.url
        }

        decisionHandler(.allow)
    }

Now you only need to know when does the new screen become visible, and use the URL you saved (To know the video URL of the new visible screen).

You can do this via listening to UIWindowDidBecomeVisibleNotification notification:

NotificationCenter.default.addObserver(self, selector: #selector(windowDidBecomeVisibleNotification(notif:)), name: NSNotification.Name("UIWindowDidBecomeVisibleNotification"), object: nil)

Then check if the navigation window is not your window, and that means a new screen did open:

@objc func windowDidBecomeVisibleNotification(notif: Notification) {
        if let isWindow = notif.object as? UIWindow {
            if (isWindow !== self.view.window) {
            print("New window did open, check what is the currect URL")
            }
        }
    }
Bacillary answered 31/3, 2019 at 16:57 Comment(21)
this method called when new window open but how i can get this avplayer item for getting video url ?Eudemon
this app feature that i wan't to do this itunes.apple.com/us/app/dmanager-browser-documents/… application is getting the same way that i wan't. can you tell me how this apps getting the video url ? detect in webview when avplayer start playing in every time and anywhere.Eudemon
please create team between you and me and i will explain you what is wan't to do .Eudemon
I am not sure why do you need the avplayer if you are seeking just the video URL. You can get video URL via my explanation. Can you please explain what you are missingBacillary
first i load the youtube.com url and when i get click on any video i want to get the video url not the current url of webview. so, your notification is fired only one time when click on video than second time your notification not fired. i want to download any video which play become in mywebviewEudemon
Mm I am pretty sure it should fire multiple times, strange.. I will check it again soonBacillary
please check this application if you capable in my above commentEudemon
@ViraniVivek I have checked my code, and it does get called on every video load full screen. I checked that app link you sent, not sure what should I do with itBacillary
but my video is inline playback in webview can you give me your code please ?Eudemon
Let us continue this discussion in chat.Eudemon
Please see the discussion chat @BacillaryEudemon
@ViraniVivek I have places a listener for ALL app notifications (Including private API's) and there is no notification with video URL info. The only access I could get is _MRMediaRemoteNowPlayingPlayerDidRegister that contains object MRContentController (Some private apple class that deals with video's probably) but can't access any props of it, and there is no documentation for that class. I think this is a dead end for KWWebView ... ):Bacillary
:) :) okay thanks for some help.MRMediaRemoteNowPlayingPlayerDidRegister what is this notifications ?Eudemon
There are a few: NSNotificationName(_rawValue: _MRMediaRemoteNowPlayingApplicationDidRegister) NSNotificationName(_rawValue: _MRMediaRemoteNowPlayingPlayerDidRegister) NSNotificationName(_rawValue: _MRMediaRemotePlayerSupportedCommandsDidChangeNotification) And also: NSNotificationName(_rawValue: AVSecondScreenConnectionPlayingDidChangeNotification) NSNotificationName(_rawValue: AVVolumeControllerVolumeChangedNotification) NSNotificationName(_rawValue: AVVolumeControllerVolumeChangedNotification) NSNotificationName(_rawValue: AVSecondScreenConnectionReadyDidChangeNotification)Bacillary
What is not working? You can definitely subscribe to there events... But there is no valid info on themBacillary
this notification is not fired i tried to my project.Eudemon
You are subscribing wrong. Add this code, it will fire all notifications, including private: NotificationCenter.default.addObserver(forName: nil, object: nil, queue: nil) { (notif) in print(notif.name) }Bacillary
please see in discussion @BacillaryEudemon
Let us continue this discussion in chat.Eudemon
have you got the solution @ViraniVivekOrison
how to check what is the currect URL @BacillaryOrison
F
3

You can try to inject JS in your WKWebView like shown here: https://paulofierro.com/blog/2015/10/12/listening-for-video-playback-within-a-wkwebview

Fornication answered 31/3, 2019 at 9:43 Comment(2)
The method he is using is no longer validBacillary
@Bacillary is right. this method not working anymore.Eudemon
M
2

retrieves the full URL from the request property of the navigation action in the webView(_:decidePolicyFor:decisionHandler:) method of WKNavigationDelegate.

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    if let urlStr = navigationAction.request.url?.absoluteString {
        //urlStr is your URL
    }

    decisionHandler(.allow)
}

also don't forgot to conform protocol

webView.navigationDelegate = self
Montymonument answered 3/4, 2019 at 6:23 Comment(2)
i want to get the actual video url not webpage url itunes.apple.com/us/app/dmanager-browser-documents/… please see this application and open youtube and select any videoEudemon
@viraniVivek I have done same for only youtube videos. I store particular video by video id which was provided by youtubeURL.Montymonument
W
1

Using Swift

You can get the html content from url of webview using code below

let docString = webView.stringByEvaluatingJavaScriptFromString("document.documentElement.outerHTML")

This case you'll get the whole html content,

Then look for href links inside the html string

let regex = try! NSRegularExpression(pattern: "<a[^>]+href=\"(.*?)\"[^>]*>")
let range = NSMakeRange(0, docString.characters.count)
let matches = regex.matches(in: docString, range: range)
for match in matches {
    let htmlLessString = (docString as NSString).substring(with: match.rangeAt(1))
    print(htmlLessString)
}

Check if it is youtube url using

Regular expression: "@https?://(www.)?youtube.com/.[^\s.,"\']+@i"

Another way to achive this

Think outside the box!

You can make an api call to get the url. That seems pretty easy using the web languages like php, .net etc.

The code for getting all urls inside a webpage in PHP (Use whatever language that is okey for you)

$url="http://wwww.somewhere.com";
$data=file_get_contents($url);
$data = strip_tags($data,"<a>");
$d = preg_split("/<\/a>/",$data);
foreach ( $d as $k=>$u ){
    if( strpos($u, "<a href=") !== FALSE ){
        $u = preg_replace("/.*<a\s+href=\"/sm","",$u);
        $u = preg_replace("/\".*/","",$u);
        print $u."\n";
    }
}

To check one by one if it is youtube url.

$sText =  "Check out my latest video here http://www.youtube.com/?123";
preg_match_all('@https?://(www\.)?youtube.com/.[^\s.,"\']+@i', $sText, $aMatches);
var_dump($aMatches);

If you wanted to check if the sample apps are using the same method, get a web debugging proxy and dig on it

Many of the above explanations are taken from other sites.

I Hope it sum up to your need! Happy coding!

Wheelchair answered 4/4, 2019 at 9:12 Comment(6)
but i want to detect video from anywebsite which open in my webview not only for youtube . for demo you can see the app in itunes the link is itunes.apple.com/us/app/dmanager-browser-documents/…Eudemon
That is php side not in swift ? can you see this app in itunes ?Eudemon
you can make an api call to backend with base url and get the filtered youtube urls as responseWheelchair
I'm getting video url without PHP only in ios swift or obj C any way even it is undocumented api i want it.Eudemon
please give me any related solution for this.Eudemon
Let us continue this discussion in chat.Eudemon
V
1

Try this in your ViewController, to add an URL Observer on WKWebView:

override func loadView() {
    let webConfig = WKWebViewConfiguration()
    webView = WKWebView(frame: .zero, configuration: webConfig)
    webView.addObserver(self, forKeyPath: "URL", options: .new, context: nil)
    view = webView
}

Overriding the observeValue to get url request:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == #keyPath(WKWebView.url) {
        let urlRequest:String = webView.url?.absoluteString ?? ""
        print(urlRequest)
    }
}

Finally... deinit the Observer:

deinit { webView.removeObserver(self, forKeyPath: "URL") }
Villanueva answered 5/4, 2019 at 13:33 Comment(1)
I'm already try it but it's give webpage url not actual videourlEudemon
S
-1

In WKWebView we need add the configuration for Inlineplacyback is true in WKWebViewConfiguration. If the configuration is set in WKWebView its automatically takes to full screen view.

Below code for reference:

class WebViewController: UIViewController {

  lazy var webView: WKWebView! = {
    
    let webView = WKWebView(frame: .zero, configuration: configuration)
    webView.translatesAutoresizingMaskIntoConstraints = false
    webView.uiDelegate = self
    webView.navigationDelegate = self
    let request = URLRequest(url: .init(string: "https://developer.apple.com/videos/play/wwdc2020/10188/")!)
    webView.load(request)
    return webView
    
  }()
  
  lazy var configuration: WKWebViewConfiguration! = {
    let configuration = WKWebViewConfiguration()
    configuration.allowsInlineMediaPlayback = true
    configuration.mediaTypesRequiringUserActionForPlayback = .audio
    configuration.allowsPictureInPictureMediaPlayback = true
    return configuration
  }()
  
  override func loadView() {
    super.loadView()
    
    self.view.backgroundColor = .white
    self.view.addSubview(self.webView)
    
    // Constraint
    
    NSLayoutConstraint.activate([
    
      self.webView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
      self.webView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
      self.webView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
      self.webView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),

    ])
    
  }

}

extension WebViewController: WKUIDelegate{
  
  
  
}

extension WebViewController: WKNavigationDelegate{
  
  
  func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse) async -> WKNavigationResponsePolicy {
    debugPrint("---------------------------- decidePolicyFor navigationResponse")
    return .allow
  }
    
  func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) {
    debugPrint("---------------------------- decidePolicyFor navigationAction")
    decisionHandler(.allow, .init())
  }
  
  
}

Click here to see sample output video

Saviour answered 29/12, 2021 at 16:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.