教你快速高效接入SDK——關於Application的適配和代理,sdkapplication

來源:互聯網
上載者:User

教你快速高效接入SDK——關於Application的適配和代理,sdkapplication

我們知道,每個android應用程式中都有一個唯一的上下文Application對象,這個Application一般我們不需要去關心他,應用啟動時,系統會自動建立一個預設的Application執行個體。但是,因為Application在整個應用中是唯一的,也就是說,他是一個單例。所以,有的應用就可能希望利用Application來完成一些工作。
好在,在android中,實現一個自訂的Application是很簡單的。直接自訂一個類繼承Application,然後在AndroidManifest.xml的application節點屬性裡將android:name設定為你自訂的這個application類即刻。
那麼,Application和U8SDK又有什麼關係呢?
這個是因為部分渠道SDK(比如百度SDK),正是在Application層級做了些事情,使得接入他們的遊戲,需要使用他們的Application,或者自訂一個Application去繼承SDK的Application,在Application對應的介面裡調用他們的方法。
但是,現在問題來了,因為U8SDK整套架構的核心思想就是,兼顧所有渠道。不可能直接在遊戲的AndroidManifest.xml中配置上某個渠道的Application或者自訂一個Application,去繼承某一個渠道的Application。然而,渠道的要求很明確的橫在中間,我們必須想辦法越過去。幸運的是,方法總是有的。在這裡,我在U8SDK抽象層中定義了一個Application監聽器IApplicationListener,同時定義一個繼承了Application類的U8Application。在U8Application類中,維護了一個IApplicationListener執行個體。這樣在U8Application的onCreate,attackBaseContext等方法中,會間接的調用IApplicationListener中相應的介面。
這樣,在具體接入渠道SDK的時候,我們就定一個適配器模式的類來繼承渠道自己的Application,同時實現U8SDK抽象層的IApplicationListener介面。然後在IApplicationListener的介面實現中,直接調用基類(渠道SDK的Application)的對應方法。
然後,遊戲層如果有自己的Application,那麼需要將該Application繼承U8Application,如果沒有自訂Application,那麼就直接將U8Application配置到AndroidManifest.xml的application節點的android:name屬性中。(怎麼配置自訂Application可以百度科普一下)。
現在關鍵的問題是,在U8SDK抽象層的U8Application中,我們怎麼知道當前需要執行個體化哪個IApplicationListener的實作類別呢?也就是說,如果百度SDK和小米SDK裡我都實現了IApplicaitonListener的實作類別。那麼,在產生渠道包的時候,怎麼樣U8Application執行個體化對應的實作類別呢?問題很簡單,我們在各個渠道接入的時候,已經定義了一個sdk_manifest.xml配置。在這個配置中,我們再加入一個配置。就是來配置這個IApplicationListener的實作類別。在applicationConfig節點的keyword後面,我們再加一個屬性:proxyApplication.這樣我們可以這樣來配置這個屬性,比如:proxyApplication=com.u8.sdk.BDProxyApplication.
這樣,我們在打包工具的指令碼在合并Manifest檔案時,加入這一段配置的解析就可以了。關於打包工具詳細的機制和原理,後續的文章會說道。如果已經購買視頻拿到源碼在使用的童鞋。可以將打包工具指令碼apk_utils.py中的mergeManifest方法改為如下形式:

def mergeManifest(targetManifest, sdkManifest):     if not os.path.exists(targetManifest) or not os.path.exists(sdkManifest):          file_utils.printF("The manifest file is not exists. targetManifest:%s, sdkManifest:%s", targetManifest, sdkManifest)          return False     ET.register_namespace('android', androidNS)     targetTree = ET.parse(targetManifest)     targetRoot = targetTree.getroot()     ET.register_namespace('android', androidNS)     sdkTree = ET.parse(sdkManifest)     sdkRoot = sdkTree.getroot()     f = open(targetManifest)     targetContent = f.read()     f.close()     bRet = False     appConfigNode = sdkRoot.find('applicationConfig')     appNode = targetRoot.find('application')         if appConfigNode != None and len(appConfigNode) > 0:          proxyApplicationName = appConfigNode.get('proxyApplication')          if proxyApplicationName != None and len(proxyApplicationName) > 0:               metaNode = SubElement(appNode, 'meta-data')               key = '{' + androidNS + '}name'               val = '{' + androidNS + '}value'               metaNode.set(key, "U8_APPLICATION_PROXY_NAME")               metaNode.set(val, proxyApplicationName)          appKeyWord = appConfigNode.get('keyword')          if appKeyWord != None and len(appKeyWord) > 0:               keyIndex = targetContent.find(appKeyWord)               if -1 == keyIndex:                    bRet = True                    for child in list(appConfigNode):                         targetRoot.find('application').append(child)     permissionConfigNode = sdkRoot.find('permissionConfig')     if permissionConfigNode != None and len(permissionConfigNode) > 0:          for child in list(permissionConfigNode):               key = '{' + androidNS + '}name'               val = child.get(key)               if val != None and len(val) > 0:                    attrIndex = targetContent.find(val)                    if -1 == attrIndex:                         bRet = True                         targetRoot.append(child)     targetTree.write(targetManifest, 'UTF-8')     return bRet

這樣,我們就實現了在U8SDK中支援了渠道自訂Application。同時,各個渠道自訂的Application也不會影響到U8SDK整體的架構。在U8SDK中,我們實現的這幾個類的源碼:

package com.u8.sdk;import android.content.Context;import android.content.res.Configuration;/*** * * 定義一個Application介面,這樣我們就可以通過該介面去間接調用渠道的Application類。 * 因為在u8sdk這套架構中,我們沒有辦法直接繼承或者直接使用某個渠道的Application。 * * @author xiaohei * */public interface IApplicationListener {     public void onProxyCreate();          public void onProxyAttachBaseContext (Context base);          public void onProxyConfigurationChanged(Configuration config);     }package com.u8.sdk;import com.u8.sdk.utils.SDKTools;import android.app.Application;import android.content.Context;import android.content.res.Configuration;/** * 我們在u8sdk抽象層中,定義一個我們自己的Application實作類別。在這個類中,我們主要是通過間接的調用 * IApplicationListener介面的方法來完成實際各個渠道Application中方法的調用。 * * 如果上層遊戲,有自己的Application。那麼可以讓該Application繼承U8Application即可。 * 如果沒有,則可以直接將U8Application配置到應用的AndroidManifest.xml的application節點 * 的android:name屬性中。 * * @author xiaohei * */public class U8Application extends Application{     private static final String DEFAULT_PKG_NAME = "com.u8.sdk";     private static final String PROXY_NAME = "U8_APPLICATION_PROXY_NAME" ;          private IApplicationListener listener;          public void onCreate(){            super.onCreate();            if( listener != null){                 listener.onProxyCreate();           }     }          public void attachBaseContext(Context base){            super.attachBaseContext(base);            this. listener = initProxyApplication();            if( this. listener != null){                 this. listener.onProxyAttachBaseContext(base);           }     }          public void onConfigurationChanged(Configuration newConfig){            super.onConfigurationChanged(newConfig);            if( this. listener != null){                 this. listener.onProxyConfigurationChanged(newConfig);           }     }          @SuppressWarnings("rawtypes")     private IApplicationListener initProxyApplication(){            String proxyAppName = SDKTools.getMetaData(this, PROXY_NAME);                       if(proxyAppName == null || SDKTools.isNullOrEmpty(proxyAppName)){                 return null;           }                       if(proxyAppName.startsWith( ".")){                proxyAppName = DEFAULT_PKG_NAME + proxyAppName;           }                       try {                Class clazz = Class. forName(proxyAppName);                 return (IApplicationListener)clazz.newInstance();                           } catch (ClassNotFoundException e) {                e.printStackTrace();           } catch (InstantiationException e) {                e.printStackTrace();           } catch (IllegalAccessException e) {                e.printStackTrace();           }                                  return null;     }}

同時,為了,驗證這套東西可行,我類比了百度SDK的情境。加入兩個類。BaiduApplication和BDProxyApplication.其中,BaiduApplication是類比百度SDK自己的Application,而BDProxyApplication則是IApplicationListener的實作類別,同時也繼承BaiduApplication。
package com.u8.sdk.bd;import android.app.Application;import android.content.Context;import android.util.Log;/** * 這個類 類比百度SDK裡面內建的Application類。 * * @author xiaohei * */public class BaiduApplication extends Application{     public void onCreate(){            super.onCreate();           Log. e("BaiduApplication" , "The onCreate of BaiduApplication called.");                }          @Override     protected void attachBaseContext(Context base) {            super.attachBaseContext(base);           Log. e("BaiduApplication" , "The attachBaseContext of BaiduApplication called.");     }     }package com.u8.sdk.bd;import com.u8.sdk.IApplicationListener;import android.content.Context;import android.content.res.Configuration;/*** * * 通過定義一個代理類,繼承百度SDK的Application,同時實現u8sdk裡,我們定義的Application監聽器介面。這樣,在監聽器方法的實現中 * 我們調用基類也就是BaiduApplication的相應方法。 * * 這樣後面,我們就可以通過調用IApplicationListener介面,實現各個渠道Application中相應方法的調用 * * @author xiaohei */public class BDProxyApplication extends BaiduApplication implements IApplicationListener{     @Override     public void onProxyCreate() {            super.onCreate();     }     @Override     public void onProxyAttachBaseContext (Context base) {            super.attachBaseContext(base);     }     @Override     public void onProxyConfigurationChanged(Configuration config) {            super.onConfigurationChanged(config);     }}


本文由小黑髮表於本部落格,轉載請註明出處.
更多精彩文章歡迎訪問小黑的部落格:http://www.uustory.com

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.