Android 는 ContentProvider 를 사용 하여 SDK 라 이브 러 리 프로젝트 소결 을 초기 화 합 니 다.

Android SDK 개발 을 할 때 는 일반적으로 초기 화 된 방법 을 패키지 로 한 다음 SDK 를 호출 한 개발 자 를 애플 리 케 이 션 의 onCreate 방법 에서 초기 화 합 니 다.그러나 현재 일부 주류 SDK 프레임 워 크 는 초기 화 하 는 방법 을 제공 하지 않 았 지만 우리 가 사용 할 때 도 정상적으로 사용 할 수 있다.그 소스 코드 를 발굴 함으로써 그들 이 일반적으로 사용 하 는 ContentProvider 를 통 해 SDK 를 초기 화 하 는 것 을 알 수 있다.현재 ContentProvider 를 사용 하 는 유명한 SDK 는 ButterKnife,Leakcanary,BlockCanary 등 이 있다.
SDK 초기 화의 본질은 무엇 입 니까?
SDK 초기 화의 본질은 앱 의 컨 텍스트(Context)를 SDK 에 주입 하여 이 컨 텍스트 를 통 해 앱 의 자원 과 서비스 에 접근 할 수 있 도록 하 는 것 이다.초기 화 할 때 SDK 방법 을 사용 하여 해당 옵션 을 사용자 정의 설정 하 는 것 도 포 함 됩 니 다.
1.ContentProvider SDK 라 이브 러 리 초기 화
ContentProvider 에서 SDK 라 이브 러 리 를 초기 화 하려 면 먼저 라 이브 러 리 에 ContentProvider 를 만 든 다음 ContentProvider 의 onCreate()방법 에서 getContext()가 돌아 오 는 Context 를 통 해 라 이브 러 리 초기 화 를 완성 해 야 합 니 다.물론 이 Context 의 실제 유형 은 응용 프로그램 입 니 다.
다음은 ContentProvider 를 통 해 SDK 라 이브 러 리 를 초기 화 하 는 예제 코드 입 니 다.

class ToolContentProvider : ContentProvider() {

    override fun onCreate(): Boolean {
        Log.e(GlobalConfig.LOG_TAG, "ToolContentProvider onCreate")
        AppContextHelper.init(context!!.applicationContext)
        AppContextHelper.initRoomDB(context!!.applicationContext)
        return true
    }

    override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? {
        return null
    }

    override fun getType(uri: Uri): String? {
        return null
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        return null
    }

    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
        return 0
    }

    override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int {
        return 0
    }
}

<provider
      android:name=".ToolContentProvider"
      android:authorities="${applicationId}.library-tool"
      android:exported="false" />

class MaoApplication : Application() {

    private lateinit var currentActivityRef: WeakReference<Activity>;


    override fun attachBaseContext(base: Context?) {
        super.attachBaseContext(base)
        Log.e(GlobalConfig.LOG_TAG, "MaoApplication attachBaseContext")
    }

    override fun onCreate() {
        super.onCreate()
        Log.e(GlobalConfig.LOG_TAG, "MaoApplication onCreate")
        initMMKV()
        initCodeView()
	}

    /**
     *    MMKV  
     */
    private fun initMMKV() {
        Log.e(GlobalConfig.LOG_TAG, "init MMKV")
        MMKV.initialize(this);
    }

    private fun initCodeView() {
        CodeProcessor.init(this)
    }

}
ContentProvider 를 통 해 SDK 라 이브 러 리 초기 화 기능 이 구현 되 었 습 니 다.그러면 ContentProvider 의 onCreate()방법 은 언제 호출 되 었 습 니까?
초기 화 시 기 를 이해 할 수 있 도록 로그 출력 입 니 다.

com.renhui.maomaomedia E/MaoMaoMedia: MaoApplication attachBaseContext
com.renhui.maomaomedia E/MaoMaoMedia: ToolContentProvider onCreate
com.renhui.maomaomedia E/MaoMaoMedia: MaoApplication onCreate
애플 리 케 이 션 의 attachBaseContext(Context)와 onCreate()사이 에서 호출 되 는 것 을 볼 수 있 습 니 다.애플 리 케 이 션 의 attachBaseContext(Context)방법 이 호출 되 었 다 는 것 은 애플 리 케 이 션 의 Context 가 초기 화 되 었 음 을 의미 합 니 다.이것 은 또한 우리 가 ContentProvider 를 통 해 SDK 라 이브 러 리 를 초기 화 할 수 있 고 실행 시간 은 Application 의 onCreate 전에 있 음 을 다시 한 번 설명 한다.
2.ContentProvider SDK 라 이브 러 리 초기 화의 장단 점
장점:
  • SDK 라 이브 러 리 를 사용 하지 않 아 도 되 는 개발 자가 라 이브 러 리 를 초기 화 하 는 절 차 를 호출 하여 접속 원 가 를 낮 추 었 습 니 다
  • 4.567917.코드 침입 이 더욱 낮 아서 SDK 라 이브 러 리 의 코드 격 리 성 을 더욱 잘 하고 업그레이드 와 유지 에 편리 합 니 다단점:
  • SDK 라 이브 러 리 의 사용 장면 이 꼭 적용 되 는 것 은 아 닙 니 다.ContentProvider 의 onCreate()가 application 의 onCreate()방법 을 실행 하기 전에 라 이브 러 리 에 다른 업무 의존 이 필요 하 다 면 이런 방식 에 적합 하지 않 습 니 다
  • 보안 구멍 문 제 를 사용 하여 구성 요소 가 노출 되 지 않도록 주의해 야 합 니 다.provider 를 설명 할 때 exported 를 false 로 설정 해 야 합 니 다
  • Provider 의 authorities 는 절대 죽음 을 쓰 지 않도록 주의해 야 한다.그렇지 않 으 면 같은 SDK 를 도입 한 두 앱 은 공존 할 수 없다
  • 3.ContentProvider 가 SDK 라 이브 러 리 를 초기 화 하 는 소스 코드 분석
    그렇다면 왜 ContentProvider 에서 초기 화 를 하면 application context 를 얻 을 수 있 습 니까?아래 몇 단락 의 소스 코드 를 보면 알 수 있다.
    
     private void handleBindApplication(AppBindData data) {
         ....
         final InstrumentationInfo ii;
         ....
         if (ii != null) {
           //1.  ContentImpl
           final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
                try {
                    final ClassLoader cl = instrContext.getClassLoader();
                    mInstrumentation = (Instrumentation)
                        cl.loadClass(data.instrumentationName.getClassName()).newInstance();
                } catch (Exception e) {
                    throw new RuntimeException(
                        "Unable to instantiate instrumentation "
                        + data.instrumentationName + ": " + e.toString(), e);
                }
    
            //2.  Instrumentation
          final ComponentName component = new ComponentName(ii.packageName, ii.name);
                mInstrumentation.init(this, instrContext, appContext, component,
                        data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
            ....
            //3.  Application  
             Application app;
             app = data.info.makeApplication(data.restrictedBackupMode, null);
    
             // Propagate autofill compat state
                app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
    
                mInitialApplication = app;
    
            ...
            //4.        ContentProvider    onCreate  
    
            if (!data.restrictedBackupMode) {
                    if (!ArrayUtils.isEmpty(data.providers)) {
                        installContentProviders(app, data.providers);
                        // For process that contains content providers, we want to
                        // ensure that the JIT is enabled "at some point".
                        mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                    }
                }
    
            //5.  Application onCreate  
            try {
                    mInstrumentation.callApplicationOnCreate(app);
                } catch (Exception e) {
                    if (!mInstrumentation.onException(app, e)) {
                        throw new RuntimeException(
                          "Unable to create application " + app.getClass().getName()
                          + ": " + e.toString(), e);
                    }
                }
        }
     }
    
    private void attachInfo(Context context, ProviderInfo info, boolean testing) {
        mNoPerms = testing;
    
        /*
         * Only allow it to be set once, so after the content service gives
         * this to us clients can't change it.
         */
        if (mContext == null) {
            mContext = context;
            if (context != null) {
                mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService (Context.APP_OPS_SERVICE);
            }
            mMyUid = Process.myUid();
            if (info != null) {
                setReadPermission(info.readPermission);
                setWritePermission(info.writePermission);
                setPathPermissions(info.pathPermissions);
                mExported = info.exported;
                mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
                setAuthorities(info.authority);
            }
            ContentProvider.this.onCreate();
        }
    }
    앱 을 시작 하 는 과정 에서 provider 를 불 러 오고 애플 리 케 이 션 인 스 턴 스 를 전송 한 것 을 볼 수 있 습 니 다.결국 ContentProvider 에서 onCreate()방법 을 호출 했 습 니 다.따라서 사용자 정의 ContentProvider 에서 getContext()방법 을 통 해 Application 의 인 스 턴 스 를 얻 을 수 있 습 니 다.
    사실 이 소스 코드 에서 도 볼 수 있 습 니 다.ContentProvider 의 onCreate()방법 은 application 의 onCreate()방법 보다 먼저 실 행 됩 니 다(주의:이때 application 대상 이 만 들 어 졌 습 니 다).
    4.구 글 의 새로운 구성 요소-App Startup
    구 글 이 출시 한 앱 스타트 업 은 앱 이 시 작 될 때 효율 적 이 고 구성 요 소 를 직접 초기 화 하 는 방법 을 제공한다.SDK 개발 자 와 앱 개발 자 모두 앱 스타트 업 을 이용 해 시작 순 서 를 간소화 하고 초기 화 순 서 를 명시 적 으로 설정 할 수 있다.App Startup 은 공 유 된 ContentProvider 통합 구성 요소 의 초기 화 를 정의 함으로써 응용 시작 시간 을 크게 단축 할 수 있다.
    프로젝트 의 초기 화가 모두 동기 화 초기 화 되 었 다 면 여러 개의 ContentProvider 를 사 용 했 을 때 App Startup 은 괜 찮 았 을 것 입 니 다.왜냐하면 하나의 ContentProvider 로 통일 되 었 고 간단 한 순서 의존 도 지 원 했 기 때 문 입 니 다.
    그러나 앱 성능 과 시동 속 도 를 추구 하 는 장면 에서 여러 SDK 가 동시에 각 사용자 정의 콘 텐 츠 제공 자 를 이용 해'셀 프 시동'을 이 루 고,다양한 선착순 과 의존 이 있 는 SDK 초기 화 에 최 적 화 를 한다 면 앱 스타트 업 은 좋 지 않 을 것 이다.공식 적 으로 는 앱 스타트 업 을 생산 환경 에 사용 하 는 것 을 권장 하지 않 는 다.
    현재 추천 방안 은 이전에 우리 가 사 용 했 던 것 입 니 다.동기 화+비동기 초기 화,무 환 도 토폴로지 정렬 방식 으로 내부 의존 구성 요소 의 초기 화 순 서 를 확보 합 니 다.
    안 드 로 이 드 가 ContentProvider 를 사용 하여 SDK 라 이브 러 리 를 초기 화 하 는 방안 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 안 드 로 이 드 가 SDK 라 이브 러 리 를 초기 화 하 는 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 지원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기