App启动加载广告页面思路

很多app在启动图加载完毕后,还会显示几秒的广告,有个跳过按钮可以跳过这个广告,有的app在点击广告页之后还会进入一个广告页面,点击返回进入首页。今天我们就来开发一个广告页面,效果如下。

Untitled 2.gif

思路

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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容