很多app在启动图加载完毕后,还会显示几秒的广告,有个跳过按钮可以跳过这个广告,有的app在点击广告页之后还会进入一个广告页面,点击返回进入首页。今天我们就来开发一个广告页面,效果如下。
思路
1.广告页加载:广告页的内容要实时显示,在没网络或者网络很差的情况下依然可以显示。所以我的做法是通过接口获取图片链接等一些信息,然后将图片异步下载到本地,并保存图片名,每次打开app时先根据本地存储的图片名查找沙盒中是否存在该图片,如果存在,则显示广告页。
2.检测广告页面是否更新。无论本地是否存在广告图片,每次打开APP都重新调用获取广告图片链接等信息的接口,根据图片名称或者其他唯一标识等方法判断广告是否更新,如果图片的唯一标识与本地保存的信息不一致,则重新下载新图片,并覆盖旧图片。
3.广告页点击。如果点击广告需要跳转广告详情页面,我的做法是将获取广告信息的接口返回的数据全部保存在本地,点击的时候从本地取出要广告的链接即可,广告详情页面是从首页跳转的。
4.广告页的显示代码可以放在AppDeleate中或者放在UITabbarController
的控制器中。如果代码是在AppDelegate中,可以通过发送通知的方式,让首页push到广告详情页,如果代码实在UITabbarController里的直接在UITabbarController里处理即可,我做法是直接将代码放在UITabbarController里。
5.主要逻辑。用户第一次打开APP的时候不显示广告,在这个时候去调用广告图片接口,将数据保存在本下载图片保存在沙盒中,用户第二打开APP的时候照样调用广告接口,并将调用接口返回的数据的唯一标识与之前本地保存的广告数据的唯一标识进行比较,如果不一样则进行现在图片并保存,用于下一次启动APP时显示。
注意:
一般广告页面的底部和启动图的底部一般都是相同的,这样给用户的感觉就是一直是同一个页面,而不是跳转到另一页面显示的。
代码:
1、自定义广告页面:
import UIKit
@objc protocol AdvertViewDelegate {
@objc optional
func onclickAdvertView(view: AdvertView)
}
class AdvertView: UIImageView {
private var btn = UIButton(type: .custom)
private var times: Int = 0
private weak var delegate: AdvertViewDelegate?
// 在global线程里创建一个时间源
private let codeTimer = DispatchSource.makeTimerSource(queue:DispatchQueue.global())
class func addAdvertView(supView: UIView, image: UIImage, times: Int, frame: CGRect, delegate: Any) {
let advertView = AdvertView(frame: frame)
supView.addSubview(advertView)
advertView.times = times;
advertView.image = image;
advertView.startCoundown()
advertView.delegate = delegate as? AdvertViewDelegate
}
override init(frame: CGRect) {
super.init(frame: frame)
isUserInteractionEnabled = true
addSubview(btn)
btn.backgroundColor = UIColor.black
btn.alpha = 0.8
btn.layer.cornerRadius = 5
btn.titleLabel?.font = UIFont.systemFont(ofSize: 12)
btn.addTarget(self, action: #selector(btnClick), for: .touchUpInside)
let tap = UITapGestureRecognizer(target: self, action: #selector(clickView))
addGestureRecognizer(tap)
}
@objc private func clickView() {
delegate?.onclickAdvertView?(view: self)
}
@objc private func btnClick() {
codeTimer.cancel()
UIView.animate(withDuration: 1.0, animations: {
self.alpha = 0.0
}, completion: { (true) in
self.removeFromSuperview()
})
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func startCoundown() {
btn.setTitle("跳过\(times)", for: .normal)
var timeCount = times + 1
// 设定这个时间源是每秒循环一次,立即开始
codeTimer.scheduleRepeating(deadline: .now(), interval: .seconds(1))
// 设定时间源的触发事件
codeTimer.setEventHandler(handler: {
// 每秒计时一次
timeCount = timeCount - 1
// 时间到了取消时间源
if timeCount <= 0 {
self.codeTimer.cancel()
DispatchQueue.main.async {
UIView.animate(withDuration: 1.0, animations: {
self.alpha = 0.0
}, completion: { (true) in
self.removeFromSuperview()
})
}
}
// 返回主线程处理一些事件,更新UI等等
DispatchQueue.main.async {
self.btn.setTitle("跳过 \(timeCount)", for: .normal)
}
})
// 启动时间源
codeTimer.resume()
}
override func layoutSubviews() {
super.layoutSubviews()
let y: CGFloat = 20.0
let width: CGFloat = 70.0
let height: CGFloat = 30.0
let x: CGFloat = screenWidth - width - 10.0
btn.frame = CGRect.init(x: x, y: y, width: width, height: height)
}
deinit {
}
}
2、UITabbarController主要代码
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//从沙盒中取出广告图片
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let imagePath = "\(path!)/\(AdvertImage).png"
guard let image = UIImage.init(contentsOfFile: imagePath) else{
return
}
AdvertView.addAdvertView(supView: self.view, image: image, times: 10, frame: CGRect.init(x: 0, y: 0, width: screenWidth, height: screenHeight), delegate: self)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
getImage()
}
// MARK: - 网络请求
extension KKMainTabBarController {
/// 下载图片
func downImage(url: URL) {
SDWebImageManager.shared().downloadImage(with: url, options: SDWebImageOptions(rawValue: 0), progress: nil, completed: { (image, error, type, animated, url) in
guard let image = image else{
return
}
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let imageData = UIImageJPEGRepresentation(image, 0.5)
guard let imgData = imageData else{
return
}
let imagepath = "\(path!)/\(AdvertImage).png"
NSData(data: imgData).write(toFile: imagepath, atomically: true)
})
}
/// 调用广告接口
func getImage() {
KKAFNetWorking.sharedManager.reqeust(url: "http://192.168.2.32/ceshi/public/index.php?s=admin/File/getAdvertImage", method: "GET") { (obj) in
guard let obj = obj else{
return
}
guard let status = obj["status"] as? String else{
return
}
if status == "200" {
guard let array = obj["data"] as? [[String: Any]] else{
return
}
guard let data = array.first else{
return
}
guard let currentid = (data["imageUrl"] as? String) else{
return
}
let userdefault = UserDefaults.standard
let dict = userdefault.value(forKey: AdvertImage) as? [String: Any]
userdefault.set(data, forKey: AdvertImage)
userdefault.synchronize()
if dict != nil {
let orgid = dict!["imageUrl"]! as! String
if currentid != orgid {
let url = URL(string: "http://192.168.2.32/ceshi/public/uploads/\(currentid)")
self.downImage(url: url!)
}else {//判断图片是否存在,
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let imagePath = "\(path!)/\(AdvertImage).png"
if ( FileManager.default.fileExists(atPath: imagePath) == false) {
let url = URL(string: "http://192.168.2.32/ceshi/public/uploads/\(currentid)")
self.downImage(url: url!)
}
}
}else{
let url = URL(string: "http://192.168.2.32/ceshi/public/uploads/\(currentid)")
self.downImage(url: url!)
}
}else{
return
}
}
}
}
获取图片接口是我自己写的,外网访问不了😞😞😞
以下是接口返回的数据
{
data = (
{
"add_time" = "2017-05-13 14:32:54";
id = 2;
imageUrl = "20170422/3.png";
}
);
message = "\U6570\U636e\U83b7\U53d6\U6210\U529f";
status = 200;
}