App啟動(dòng)廣告頁(yè)的實(shí)現(xiàn)和封裝

歡迎訪問我的博客muhlenXi,該文章出自我的博客。

版權(quán)聲明:本文為muhlenXi原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處,未經(jīng)允許不得轉(zhuǎn)載.

導(dǎo)語(yǔ):

也許你也注意到了,現(xiàn)在很多App在啟動(dòng)頁(yè)加載完畢后,還會(huì)出現(xiàn)一個(gè)n秒的廣告頁(yè)面,頁(yè)面中有一個(gè)倒計(jì)時(shí)的按鈕,我們可以通過點(diǎn)擊跳過那個(gè)按鈕來(lái)跳過,我們點(diǎn)擊廣告的時(shí)候,會(huì)進(jìn)入廣告的詳情頁(yè)面。如果我們不做任何操作的話,當(dāng)?shù)褂?jì)時(shí)為0秒是會(huì)自動(dòng)進(jìn)入主頁(yè)面。

接下來(lái)我們就研究研究這個(gè)是如何實(shí)現(xiàn)的。

解決方案

我們仔細(xì)想想:不妨也有兩種思路來(lái)解決。

  • 1、一種是App初次運(yùn)行時(shí),將廣告頁(yè)面的圖片URL和要點(diǎn)擊廣告要跳轉(zhuǎn)的URL數(shù)據(jù)通過服務(wù)器下載下來(lái),然后再異步下載圖片數(shù)據(jù),最后將圖片的數(shù)據(jù)和跳轉(zhuǎn)URL保存到本地沙盒中。第二次運(yùn)行App的時(shí)候會(huì)顯示廣告界面,這時(shí)候再通過服務(wù)器更新本地沙盒中的數(shù)據(jù)。第一次由于本地沙盒中沒有數(shù)據(jù)則不會(huì)顯示。目前大部分App采用此方式

  • 2、第二種是每次啟動(dòng)時(shí)就通過服務(wù)器異步下載圖片數(shù)據(jù)和跳轉(zhuǎn)URL,然后將其顯示出來(lái)。這樣做的優(yōu)點(diǎn)時(shí),可以實(shí)時(shí)更新廣告頁(yè)面數(shù)據(jù)。缺點(diǎn)是當(dāng)網(wǎng)絡(luò)出現(xiàn)阻塞時(shí)或無(wú)網(wǎng)絡(luò)時(shí),會(huì)出現(xiàn)一個(gè)空白的廣告界面。

    針對(duì)該缺點(diǎn),有一個(gè)解決思路,就是當(dāng)網(wǎng)絡(luò)不好時(shí),用一個(gè)固定的圖片和跳轉(zhuǎn)URL來(lái)替換或者只用一個(gè)固定的圖片來(lái)替換,點(diǎn)擊廣告則不跳轉(zhuǎn)。但是當(dāng)跳轉(zhuǎn)URL失效時(shí),需要通過迭代版本,重新上架來(lái)更新,周期比較長(zhǎng)。

第一種方案。

請(qǐng)點(diǎn)擊這里查看演示視頻

XYJAdvertisementView的實(shí)現(xiàn)

Xcode中通過File -> New ->File... 新建一個(gè)繼承與UIVIewXYJLaunchAdvertisingView;

編寫程序的核心在于要有一個(gè)完整的思路!其次為了高效率的編程,我們需要學(xué)會(huì)一些偷懶的方法,比如宏定義的使用、類型常量的使用、變量的高效命名...

【1】在XYJAdvertisementView.h文件中,我們需要幾個(gè)宏定義和類型常量。代碼如下:

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
#define kScreenBounds [UIScreen mainScreen].bounds
static NSString * const adImageName = @"adImageName";
static NSString * const adDownloadUrl = @"adDownloadUrl";
static NSInteger  const adTime = 3;
static NSString * const pushToADNotiName = @"pushToADNotiName";
static NSString * const pushToADUrl = @"pushToADUrl";

我們還需聲明一個(gè)圖片路徑和一個(gè)顯示廣告的show方法。

@property (nonatomic,copy) NSString * filePath; //!<  ?圖片路徑 用于屬性傳值
- (void) showAD;  //顯示廣告頁(yè)面方法

【2】在XYJAdvertisementView.m文件中,在匿名類中聲明我們需要的控件。

聲明如下:

@property (nonatomic,strong) UIImageView * adImageView;
@property (nonatomic,strong) UIButton * countBtn;  //倒計(jì)時(shí)
@property (nonatomic,strong) NSTimer  * countTimer;
@property (nonatomic,assign) NSInteger  count;  //記錄當(dāng)前的秒數(shù)

接下來(lái)我們依次實(shí)現(xiàn)相應(yīng)的方法,我們要記住高內(nèi)聚低耦合的原則

通過重寫initWithFrame方法來(lái)搭建我們的UI界面

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        //其他控件的初始化寫在這里
        //1.廣告圖片
        _adImageView = [[UIImageView alloc] initWithFrame:frame];
        _adImageView.userInteractionEnabled = YES;
        _adImageView.backgroundColor =  [UIColor yellowColor];
        _adImageView.contentMode = UIViewContentModeScaleAspectFill;
        _adImageView.clipsToBounds = YES;
        UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesHandle:)];
        [_adImageView addGestureRecognizer:tap];
        //2.跳過按鈕
        CGFloat btnW = 60.0f;
        CGFloat btnH = 30.0f;
        _countBtn = [[UIButton alloc] initWithFrame:CGRectMake(kScreenWidth-btnW-24, btnH, btnW, btnH)];
        [_countBtn addTarget:self action:@selector(dismissAD) forControlEvents:UIControlEventTouchUpInside];
        _countBtn.titleLabel.font = [UIFont systemFontOfSize:15];
        [_countBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [_countBtn setTitle:[NSString stringWithFormat:@"跳過%ld",adTime] forState:UIControlStateNormal];
        _countBtn.backgroundColor = [UIColor colorWithRed:38/255.0 green:38/255.0 blue:38/255.0 alpha:0.6];
        _countBtn.layer.cornerRadius = 4;
        [self addSubview:_adImageView];
        [self addSubview:_countBtn];
    }
    return self;
}
  • 通過懶加載的方式實(shí)現(xiàn)我們的定時(shí)器countTimer*

    所謂的懶加載也就是延時(shí)加載,即當(dāng)對(duì)象需要用到的時(shí)候再去加載,簡(jiǎn)單理解就是,重寫對(duì)象的get方法。當(dāng)我們重寫get方法時(shí),一定要注意,先要判斷當(dāng)前對(duì)象是否為空,為空的話再去實(shí)例化對(duì)象。

    懶加載的優(yōu)點(diǎn)如下:
    1、對(duì)象的實(shí)例化在get方法中實(shí)現(xiàn),可以降低耦合度。
    2、不需要在viewDidLoad中再實(shí)例化對(duì)象,可以簡(jiǎn)化代碼,同時(shí)增強(qiáng)代碼的可讀性。
    3、有效減少內(nèi)存的占用率。

代碼如下:

- (NSTimer *)countTimer
{
    if (_countTimer == nil) {
       _countTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(countDownEventHandle) userInfo:nil repeats:YES];
    }
    return _countTimer;
}

實(shí)現(xiàn)我們的事件響應(yīng)方法

//廣告界面點(diǎn)擊
- (void) tapGesHandle:(UITapGestureRecognizer *) tap
{
   [self dismissAD];
   [[NSNotificationCenter defaultCenter] postNotificationName:pushToADNotiName object:nil userInfo:nil];
}
//定時(shí)器響應(yīng)
- (void) countDownEventHandle
{
    _count--;
    [_countBtn setTitle:[NSString stringWithFormat:@"跳過%ld",_count] forState:UIControlStateNormal];
    if (_count == 0) {
        [self dismissAD];
    }
}
//跳過按鈕觸發(fā)
- (void) dismissAD
{
    [self.countTimer invalidate];
    self.countTimer = nil;
    [UIView animateWithDuration:0.3 animations:^{
    self.alpha = 0;
    } completion:^(BOOL finished) {
       [self removeFromSuperview];
    }];
}

實(shí)現(xiàn)我們前面聲明的Show方法

//啟動(dòng)定時(shí)器
- (void) startTimer
{
    _count = adTime;
    [[NSRunLoop mainRunLoop] addTimer:self.countTimer forMode:NSRunLoopCommonModes];
}
//顯示廣告頁(yè)面
- (void)showAD
{
    [self startTimer];
    UIWindow * window = [UIApplication sharedApplication].keyWindow;
    [window addSubview:self];
}
//圖片賦值
- (void)setFilePath:(NSString *)filePath
{
    _filePath = filePath;
    _adImageView.image = [UIImage imageWithContentsOfFile:filePath];
}

到這里,我們的View就定制完成,我們還需要一個(gè)數(shù)據(jù)管理類來(lái)管理沙盒中的廣告數(shù)據(jù)!

數(shù)據(jù)管理類XYJADDataManager的實(shí)現(xiàn)

通過File -> New ->File... 新建一個(gè)繼承與NSObjectXYJADDataManager;

【1】在XYJADDataManager.h文件中,聲明一個(gè)添加廣告的方法聲明。代碼如下:

導(dǎo)入頭文件:

#import "XYJAdvertisementView.h"

方法聲明:

+ (void) addXYJAdvertisementView;

【2】在XYJADDataManager.m文件中,實(shí)現(xiàn)相應(yīng)的方法。代碼如下:

在實(shí)現(xiàn)show方法之前,我們要先實(shí)現(xiàn)一些幫助方法

通過圖片的名字獲取該圖片在沙盒中的絕對(duì)路徑

+ (NSString *)getFilePathWithImageName:(NSString *)imageName
{
    if (imageName) {
        NSArray * paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
        //圖片默認(rèn)存儲(chǔ)在Cache目錄下
        return [paths[0] stringByAppendingPathComponent:imageName];
    }
    return nil;
}

判斷該路徑下是否存在文件

+ (BOOL)isFileExistWithFilePath:(NSString *) filePath
{
    NSFileManager * fileManager = [NSFileManager defaultManager];
    BOOL isDirectory = NO;
    return [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];   
}

刪除舊的圖片

+ (void) deleteOldImage
{
    NSString * imageName = [[NSUserDefaults standardUserDefaults] objectForKey:adImageName];
    if (imageName) {
        NSString * filePath = [self getFilePathWithImageName:imageName];
        NSFileManager * fileManager = [NSFileManager defaultManager];
        if ([self isFileExistWithFilePath:filePath]) {
            [fileManager removeItemAtPath:filePath error:nil];
        }
    }
}

向服務(wù)器請(qǐng)求廣告數(shù)據(jù)

該方法中要根據(jù)實(shí)際項(xiàng)目需求做相應(yīng)調(diào)整

+ (void) UpdateAdvertisementDataFromServer
{
    //TODO 在這里請(qǐng)求廣告的數(shù)據(jù),包含圖片的圖片路徑和點(diǎn)擊圖片要跳轉(zhuǎn)的URL
    //我們這里假設(shè)從服務(wù)器中獲得的 圖片的下載URl和跳轉(zhuǎn)URl如下所示
    NSString * imageurl = @"http://pic.paopaoche.net/up/2012-2/20122220201612322865.png";
    NSString * pushtoURl = @"http://www.itdecent.cn";
    //獲取圖片名
   NSString * imageName = [[imageurl componentsSeparatedByString:@"/"] lastObject];
   //將圖片名與沙盒中的數(shù)據(jù)比較
    NSString * oldImageName =[[NSUserDefaults standardUserDefaults] objectForKey:adImageName];
    if ((oldImageName == nil) || (![oldImageName isEqualToString:imageName]) ) {
        //異步下載廣告數(shù)據(jù)
        [self downloadADImageWithUrl:imageurl iamgeName:imageName];
        //保存跳轉(zhuǎn)路徑到沙盒中
        [[NSUserDefaults standardUserDefaults] setObject:pushtoURl forKey:pushToADUrl];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
 }

異步下載圖片數(shù)據(jù)

+ (void) downloadADImageWithUrl:imageUrl iamgeName:(NSString *) imageName
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //TODO 異步操作
        //1、下載數(shù)據(jù)
        NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]];
        UIImage * image = [UIImage imageWithData:data];
        //2、獲取保存文件的路徑
        NSString * filePath = [self getFilePathWithImageName:imageName];
        //3、寫入文件到沙盒中
        BOOL ret = [UIImagePNGRepresentation(image) writeToFile:filePath atomically:YES];
        if (ret) {
            NSLog(@"廣告圖片保存成功");
            [self deleteOldImage];
            //保存?圖片名和下載路徑
            [[NSUserDefaults standardUserDefaults] setObject:imageName forKey:adImageName];
            [[NSUserDefaults standardUserDefaults] setObject:imageUrl forKey:adDownloadUrl];
            [[NSUserDefaults standardUserDefaults] synchronize];
        } else {
            NSLog(@"廣告圖片保存失敗");
        }
    });
}

實(shí)現(xiàn)addXYJAdvertisementView方法

+ (void) addXYJAdvertisementView;
{
    //1.判斷沙盒中是否存在廣告的圖片名字和圖片數(shù)據(jù),如果有則顯示
    NSString * imageName = [[NSUserDefaults standardUserDefaults] objectForKey:adImageName];
    if (imageName != nil)
    {
        NSString * filePath = [self getFilePathWithImageName:imageName];
        BOOL isExist = [self isFileExistWithFilePath:filePath];
        //本地存在圖片
        if (isExist) {
            NSLog(@"本地存在圖片");
            XYJAdvertisementView * adView = [[XYJAdvertisementView alloc] initWithFrame:kScreenBounds];
            adView.filePath = filePath;
            [adView showAD];
        }
}
    //更新本地廣告數(shù)據(jù)
    [self UpdateAdvertisementDataFromServer];
}

最后一步,在AppDelegate文件中添加廣告

  • 1、在AppDelegate.h文件中導(dǎo)入XYJADDataManager.h文件 。
  • 2、在didFinishLaunchingWithOptions方法中加入如下代碼即可。
//添加啟動(dòng)廣告
[XYJADDataManager addXYJAdvertisementView];
  • 3、如果你需要獲取廣告點(diǎn)擊事件,則需要進(jìn)行如下操作。

在主界面ViewController的viewDidLoad方法中添加:

//添加廣告點(diǎn)擊的監(jiān)聽
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pushToADVC) name:pushToADNotiName object:nil];

同時(shí)實(shí)現(xiàn)事件響應(yīng)方法:

- (void) pushToADVC
{
    //TODO 在這里處理廣告事件響應(yīng)
    NSLog(@"廣告點(diǎn)擊了");
    XYJADWebViewController * webVC = [[XYJADWebViewController alloc] init];
    webVC.url = [[NSUserDefaults standardUserDefaults] objectForKey:pushToADUrl];
    [self.navigationController pushViewController:webVC animated:YES];
}

編譯運(yùn)行后,會(huì)發(fā)現(xiàn)跟我們前面的效果展示是一樣的。

點(diǎn)這里下載完整Demo

目前暫無(wú)實(shí)現(xiàn)第二種方案

感謝閱讀,有什么建議可以給我留言

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容