314 lines
10 KiB
Swift
314 lines
10 KiB
Swift
//
|
||
// WebViewController.swift
|
||
// yinmeng-ios
|
||
//
|
||
// Created by yinmeng on 2024/2/26.
|
||
//
|
||
|
||
import UIKit
|
||
import WebKit
|
||
import MJExtension
|
||
class WebViewWeakScriptMessage: NSObject, WKScriptMessageHandler {
|
||
|
||
private(set) weak var target: WKScriptMessageHandler?
|
||
|
||
required init(target: WKScriptMessageHandler?) {
|
||
self.target = target
|
||
|
||
}
|
||
|
||
|
||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||
target?.userContentController(userContentController, didReceive: message)
|
||
}
|
||
|
||
}
|
||
|
||
class WebViewController: BaseViewController {
|
||
|
||
typealias OnReceiveMessage = (_ msg: WKScriptMessage) -> Void
|
||
|
||
private(set) lazy var webview = makeWebView()
|
||
|
||
private(set) var progressView = UIProgressView()
|
||
|
||
|
||
private lazy var userContentController:WKUserContentController = {
|
||
let scriptMessage = WebViewWeakScriptMessage(target: self);
|
||
|
||
let _userContentController = WKUserContentController()
|
||
_userContentController.add(self, name: "getUid")
|
||
_userContentController.add(self, name: "getDeviceId")
|
||
_userContentController.add(self, name: "getTicket")
|
||
_userContentController.add(self, name: "getDeviceInfo")
|
||
_userContentController.add(self, name: "initShowNav")
|
||
_userContentController.add(self, name: "closeWebView")
|
||
_userContentController.add(self, name: "cancelAccount")
|
||
return _userContentController
|
||
}()
|
||
private var callbacks: [String: [OnReceiveMessage]] = [:]
|
||
|
||
private(set) weak var navigationDelegate: WKNavigationDelegate?
|
||
|
||
private(set) var url: String?
|
||
var isHalf:Bool = false
|
||
convenience init(
|
||
url: String?,
|
||
navigationDelegate: WKNavigationDelegate? = nil,isHalf:Bool = false
|
||
) {
|
||
self.init(nibName: nil, bundle: nil)
|
||
self.url = url
|
||
self.isHalf = isHalf
|
||
if var url = url {
|
||
if !url.hasPrefix("http") {
|
||
url = "\(AppKeys.H5_URL)/\(url)"
|
||
}
|
||
self.url = url
|
||
}
|
||
self.navigationDelegate = navigationDelegate
|
||
}
|
||
|
||
override func viewDidLoad() {
|
||
super.viewDidLoad()
|
||
loadSubViews()
|
||
loadWebView()
|
||
}
|
||
deinit{
|
||
print("1111")
|
||
}
|
||
override func viewWillAppear(_ animated: Bool) {
|
||
super.viewWillAppear(animated)
|
||
addObserve()
|
||
}
|
||
|
||
override func viewWillDisappear(_ animated: Bool) {
|
||
super.viewWillDisappear(animated)
|
||
removeObserve()
|
||
}
|
||
|
||
override func viewDidLayoutSubviews() {
|
||
super.viewDidLayoutSubviews()
|
||
|
||
view.bringSubviewToFront(progressView)
|
||
}
|
||
|
||
private func loadSubViews() {
|
||
|
||
if self.isHalf{
|
||
let bakcBtn = UIButton()
|
||
bakcBtn.addTarget(self, action: #selector(dissViewAction), for: .touchUpInside)
|
||
view.addSubview(bakcBtn)
|
||
bakcBtn.snp.makeConstraints { make in
|
||
make.edges.equalTo(view)
|
||
}
|
||
view.addSubview(webview)
|
||
view.addSubview(progressView)
|
||
progressView.snp.makeConstraints { make in
|
||
make.top.equalTo(view).offset(0)
|
||
make.left.right.equalTo(view).offset(0)
|
||
make.height.equalTo(1)
|
||
}
|
||
view.backgroundColor = .clear
|
||
webview.snp.makeConstraints { make in
|
||
|
||
make.left.bottom.right.equalTo(view)
|
||
make.height.equalTo(ScreenHeight * 0.65)
|
||
}
|
||
}else{
|
||
view.addSubview(webview)
|
||
view.addSubview(progressView)
|
||
progressView.snp.makeConstraints { make in
|
||
make.top.equalTo(view).offset(0)
|
||
make.left.right.equalTo(view).offset(0)
|
||
make.height.equalTo(1)
|
||
}
|
||
webview.snp.makeConstraints { make in
|
||
make.top.equalTo(view).offset(1)
|
||
make.left.right.bottom.equalTo(view)
|
||
}
|
||
}
|
||
|
||
|
||
progressView.trackTintColor = .clear
|
||
progressView.transform = .init(scaleX: 1, y: 1.5)
|
||
progressView.alpha = 0
|
||
}
|
||
|
||
@objc func dissViewAction(){
|
||
self.dismiss(animated: true)
|
||
}
|
||
|
||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||
if let object = object as? WKWebView, object == webview {
|
||
if keyPath == "estimatedProgress" {
|
||
progressView.setProgress(Float(webview.estimatedProgress), animated: true)
|
||
return
|
||
}
|
||
}
|
||
|
||
if keyPath == "title" {
|
||
title = webview.title
|
||
return
|
||
}
|
||
}
|
||
|
||
func addObserve() {
|
||
//添加KVO,WKWebView有一个属性estimatedProgress,就是当前网页加载的进度,所以监听这个属性
|
||
webview.addObserver(self, forKeyPath: "estimatedProgress", context: nil)
|
||
//添加KVO,监听title属性
|
||
webview.addObserver(self, forKeyPath: "title", context: nil)
|
||
}
|
||
|
||
func removeObserve() {
|
||
webview.removeObserver(self, forKeyPath: "estimatedProgress")
|
||
webview.removeObserver(self, forKeyPath: "title")
|
||
}
|
||
|
||
func loadWebView() {
|
||
guard let url = url,
|
||
let theUrl = URL(string: url),
|
||
let _ = theUrl.scheme,
|
||
let _ = theUrl.host else {
|
||
return
|
||
}
|
||
|
||
webview.load(URLRequest(url: theUrl))
|
||
|
||
}
|
||
|
||
|
||
|
||
func reloadWebViewWithUrl(_ url: String) {
|
||
self.url = url
|
||
loadWebView()
|
||
}
|
||
|
||
func makeWebView() -> WKWebView {
|
||
let configuration = WKWebViewConfiguration()
|
||
configuration.mediaTypesRequiringUserActionForPlayback = .all
|
||
configuration.allowsInlineMediaPlayback = true
|
||
configuration.allowsPictureInPictureMediaPlayback = true
|
||
configuration.selectionGranularity = .character
|
||
|
||
let cookie = "uid=\(AuthManager.userUid)"
|
||
let cookieScript = WKUserScript.init(source: "document.cookie = '\(cookie)';", injectionTime: .atDocumentStart, forMainFrameOnly: false)
|
||
self.userContentController.addUserScript(cookieScript)
|
||
|
||
let scale = "$('meta[name=description]').remove(); $('head').append( '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1,user-scalable=no\">' );"
|
||
|
||
let scaleScript = WKUserScript.init(source: scale, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
|
||
self.userContentController.addUserScript(scaleScript)
|
||
configuration.userContentController = self.userContentController
|
||
|
||
|
||
let preferences = WKPreferences()
|
||
if #available(iOS 14, *) {
|
||
let webpagePreferences = WKWebpagePreferences()
|
||
webpagePreferences.allowsContentJavaScript = true
|
||
configuration.defaultWebpagePreferences = webpagePreferences
|
||
} else {
|
||
preferences.javaScriptEnabled = true
|
||
}
|
||
preferences.javaScriptCanOpenWindowsAutomatically = true
|
||
preferences.minimumFontSize = 10
|
||
configuration.preferences = preferences
|
||
let webview = WKWebView(frame: UIScreen.main.bounds, configuration: configuration)
|
||
webview.navigationDelegate = self
|
||
webview.evaluateJavaScript("navigator.userAgent") {[weak self] res, error in
|
||
guard let self = self else{return}
|
||
if let text = res as? NSString{
|
||
if !text.contains("tutuAppIos erbanAppIos"){
|
||
let newText = (text as String) + "tutuAppIos erbanAppIos"
|
||
let dic = ["UserAgent":newText]
|
||
UserDefaults.standard.register(defaults: dic)
|
||
UserDefaults.standard.synchronize()
|
||
self.webview.customUserAgent = newText
|
||
}
|
||
}
|
||
}
|
||
return webview
|
||
}
|
||
|
||
func dicValueString(_ dic:[String:Any]) ->String? {
|
||
let data = try? JSONSerialization.data(withJSONObject: dic,options: [])
|
||
let str = String(data: data!,encoding:String.Encoding.utf8)
|
||
return str
|
||
}
|
||
|
||
}
|
||
|
||
extension WebViewController: WKScriptMessageHandler {
|
||
|
||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||
//TODO: 拦截一些h5的事件
|
||
webview.evaluateJavaScript("document.location.href") {[weak self] res, error in
|
||
guard let self = self else{return}
|
||
if let curUrl = res{
|
||
if message.name == "getUid"{
|
||
let uid = "getMessage(\"uid\",\(AuthManager.userUid))"
|
||
self.webview.evaluateJavaScript(uid) { other, error in
|
||
|
||
}
|
||
}else if message.name == "getTicket"{
|
||
let ticket = "getMessage(\"ticket\",\"\(AuthManager.ticket)\")"
|
||
self.webview.evaluateJavaScript(ticket) { other, error in
|
||
|
||
}
|
||
}else if message.name == "getDeviceId"{
|
||
let deviceId = "getMessage(\"deviceId\",\"\(APPUtils.currentDeveiceId)\")"
|
||
self.webview.evaluateJavaScript(deviceId) { other, error in
|
||
|
||
}
|
||
}else if message.name == "getDeviceInfo"{
|
||
let info = NSDictionary(dictionary: YMNetworkHelper.share.baseParameters)
|
||
if let infoText = info.mj_JSONString() {
|
||
let text = "getMessage(\"deviceInfo\",\(infoText))"
|
||
self.webview.evaluateJavaScript(text) { other, error in
|
||
|
||
}
|
||
}
|
||
|
||
}else if message.name == "initShowNav"{
|
||
if let body = message.body as? Int,body == 0{
|
||
if self.navigationController != nil{
|
||
self.navigationController?.setNavigationBarHidden(true, animated: false)
|
||
}
|
||
}
|
||
}else if message.name == "closeWebView"{
|
||
if let body = message.body as? Int,body == 0{
|
||
if self.navigationController != nil{
|
||
self.navigationController?.popViewController(animated: true)
|
||
}
|
||
}
|
||
}else if message.name == "cancelAccount"{
|
||
AuthViewModel.authVM.logout()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
extension WebViewController: WKNavigationDelegate{
|
||
|
||
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
||
progressView.alpha = 1
|
||
navigationDelegate?.webView?(webview, didStartProvisionalNavigation: navigation)
|
||
}
|
||
|
||
|
||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||
UIView.animate(withDuration: 0.2) {
|
||
self.progressView.alpha = 0
|
||
}
|
||
navigationDelegate?.webView?(webview, didFinish: navigation)
|
||
}
|
||
|
||
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
||
UIView.animate(withDuration: 0.2) {
|
||
self.progressView.alpha = 0
|
||
}
|
||
navigationDelegate?.webView?(webView, didFailProvisionalNavigation: navigation, withError: error)
|
||
}
|
||
|
||
}
|