淘宝atlas框架初探atlas-core(二):Bundle插件化

本文深入探讨淘宝Atlas框架的组件插件化,重点在于Bundle的加载和管理。通过分析AtlasDemo MainActivity,揭示了如何利用bundle机制实现组件的动态加载。Atlas不仅创建了自己的组件体系,还兼容了Android原生的Activity组件,实现了一套完整的插件化解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇《淘宝Atlas框架初探atlas-core(一)》我们研究了淘宝模块化apk:bundle体系,还有bundle体系配套的hook体系。

本篇我们继续研究一下atlas框架的四大组件插件化。

第一篇的分析中我们了解到bundle体系已经为组件的插件化做了准备。下面我们看atlas如何运用bundle机制动态完成bundle的加载,我们看AtlasDemo MainActivity怎么做的。

    private ActivityGroupDelegate mActivityDelegate;
    private ViewGroup mActivityGroupContainer;

    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_home:
                    switchToActivity("home","com.taobao.firstbundle.FirstBundleActivity");
                    return true;
                case R.id.navigation_dashboard:
                    switchToActivity("second","com.taobao.secondbundle.SecondBundleActivity");
                    return true;
                case R.id.navigation_notifications:

                    return true;
            }
            return false;
        }

    };


    public void switchToActivity(String key,String activityName){
        Intent intent = new Intent();
        intent.setClassName(getBaseContext(),activityName);
        mActivityDelegate.startChildActivity(mActivityGroupContainer,key,intent);
    }
MainActivity通过ActivityGroupDelegate的startChildActivity实现Bundle的切换

    public void startChildActivity(ViewGroup container, String key, Intent intent){
        //移除内容部分全部的View
        container.removeAllViews();
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        Activity contentActivity = mLocalActivityManager.getActivity(key);
        if(contentActivity!=null) {
            container.addView(
                    mLocalActivityManager.getActivity(key)
                            .getWindow().getDecorView(),
                    new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.MATCH_PARENT));
            mLocalActivityManager.switchToChildActivity(key);
        }else{
            execStartChildActivityInternal(container, key, intent);
        }
    }

我们找到了关键的LocalActivityManager,从功能上看和正常的ActivityManager是相同的,


它管理了所有Activity的所有状态,控制Activity之间的切换。将正常的远程Binder调用变成了本地管理。

    public void execStartChildActivityInternal(ViewGroup container,String key, Intent intent){
        String packageName = null;
        String componentName = null ;
        Context context = container.getContext();
        if (intent.getComponent() != null) {
            packageName = intent.getComponent().getPackageName();
            componentName = intent.getComponent().getClassName();
        } else {
            ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0);
            if (resolveInfo != null && resolveInfo.activityInfo != null) {
                packageName = resolveInfo.activityInfo.packageName;
                componentName = resolveInfo.activityInfo.name;
            }
        }
        if (componentName == null){
            Log.e("ActivityGroupDelegate","can not find componentName");
        }
        if (!StringUtils.equals(context.getPackageName(), packageName)) {
            Log.e("ActivityGroupDelegate","childActivity can not be external Activity");
        }

        String bundleName = AtlasBundleInfoManager.instance().getBundleForComponet(componentName);
        if(!TextUtils.isEmpty(bundleName)){
            BundleImpl impl = (BundleImpl) Atlas.getInstance().getBundle(bundleName);
            if(impl!=null&&impl.checkValidate()) {
                performLaunchChildActivity(container,key,intent);
            }else {
                if(ActivityTaskMgr.getInstance().peekTopActivity()!=null && Looper.getMainLooper().getThread().getId()==Thread.currentThread().getId()) {
                    asyncStartActivity(container,key,bundleName,intent);
                }else{
                    performLaunchChildActivity(container,key,intent);
                }
            }
        }else{
            // Try to get class from system Classloader
            try {
                Class<?> clazz = null;
                clazz = Framework.getSystemClassLoader().loadClass(componentName);
                if (clazz != null) {
                    performLaunchChildActivity(container,key,intent);
                }
            } catch (ClassNotFoundException e) {
                Log.e("ActivityGroupDelegate",e.getCause().toString());
            }
        }

    }

第一次进入Activity的时候先走execStartChildActivityInternal(container, key, intent);

public String getBundleForComponet(String componentName){
        InitBundleInfoByVersionIfNeed();
        if (mCurrentBundleListing == null ||
                   mCurrentBundleListing.getBundles() == null || 
                   mCurrentBundleListing.getBundles().size() == 0){
            return findBundleByComponentName(componentName);
        }
......
}

 /**
     * 根据版本载入清单
     */
    private synchronized void InitBundleInfoByVersionIfNeed(){
        if(mCurrentBundleListing==null){
            String bundleInfoStr = null;
            try {
                Field field = FrameworkProperties.class.getDeclaredField("bundleInfo");
                field.setAccessible(true);
                bundleInfoStr = (String)field.get(FrameworkProperties.class);
            }catch(Throwable e){
                e.printStackTrace();
            }

            if(!TextUtils.isEmpty(bundleInfoStr)) {
                try {
                    LinkedHashMap<String,BundleListing.BundleInfo> infos = BundleListingUtil.parseArray(bundleInfoStr);
                    BundleListing listing = new BundleListing();
                    listing.setBundles(infos);
                    mCurrentBundleListing = listing;
                }catch(Throwable e){
                    e.printStackTrace();
                }
            }else{
                throw new RuntimeException("read bundleInfo failed");
            }
        }

    }
根据版本载入不同的清单,可以在FrameworkProperties.class中设置大版本的Bundle信息

如果BundleList为空,则进入AtlasBundleInfoManager 的getBundleForComponet

    private String findBundleByComponentName(String componentClassName){
        getComponentInfoFromManifestIfNeed();
        ComponentName componentName = new ComponentName(RuntimeVariables.androidApplication.getPackageName(),componentClassName);
        if(activityInfos!=null){
            ActivityInfo info = activityInfos.get(componentClassName);
            if(info!=null){
                if(info.metaData!=null){
                    return info.metaData.getString("bundleLocation");
                }else {
                    try {
                        ActivityInfo detailInfo = RuntimeVariables.androidApplication.getPackageManager().getActivityInfo(componentName, PackageManager.GET_META_DATA);
                        if (detailInfo != null && detailInfo.metaData != null) {
                            info.metaData = detailInfo.metaData;
                            return detailInfo.metaData.getString("bundleLocation");
                        } else {
                            return null;
                        }
                    } catch (Throwable e) {
                    }
                }
            }
        }
......
}
getComponemntInfoFromManifestIfNeed获取所有对应包名的Manifest里面四大组件的信息,然后保存到AtlasBundleInfoManager本地,日后提供给ActivityGroupDelegate调用,我们继续看对应Activity的manifest。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.taobao.firstbundle">

    <application
        android:allowBackup="true"
        android:supportsRtl="true">
        <activity
            android:name=".FirstBundleActivity"
            android:theme="@style/AppTheme.NoActionBar" />

        <service
            android:name=".FirstBundleService"
            android:enabled="true"
            android:exported="true"></service>
    </application>

</manifest>

demo里面并没有“bundleLocation”的meta信息,

        if(activityInfos!=null){
            ActivityInfo info = activityInfos.get(componentClassName);
            if(info!=null){
                if(info.metaData!=null){
                    return info.metaData.getString("bundleLocation");
                }else {
                    try {
                        ActivityInfo detailInfo = RuntimeVariables.androidApplication.getPackageManager().getActivityInfo(componentName, PackageManager.GET_META_DATA);
                        if (detailInfo != null && detailInfo.metaData != null) {
                            info.metaData = detailInfo.metaData;
                            return detailInfo.metaData.getString("bundleLocation");
                        } else {
                            return null;
                        }
                    } catch (Throwable e) {
                    }
                }
            }
        }

看流程,没有meta值bundleLocation,bundle的activity就启动不了,所以这个bundle值可能在编译的时候动态设置的,这个bundleLocation我们在update篇在继续分析,这里我们先继续。我们回到ActivityGroupDelegate的execStartChildActivityInternal方法

 public void execStartChildActivityInternal(ViewGroup container,String key, Intent intent){

    ......
        String bundleName = AtlasBundleInfoManager.instance().getBundleForComponet(componentName);
        if(!TextUtils.isEmpty(bundleName)){
            BundleImpl impl = (BundleImpl) Atlas.getInstance().getBundle(bundleName);
            if(impl!=null&&impl.checkValidate()) {
                performLaunchChildActivity(container,key,intent);
            }else {
                if(ActivityTaskMgr.getInstance().peekTopActivity()!=null && Looper.getMainLooper().getThread().getId()==Thread.currentThread().getId()) {
                    asyncStartActivity(container,key,bundleName,intent);
                }else{
                    performLaunchChildActivity(container,key,intent);
                }
            }
        }else{
            // Try to get class from system Classloader
            try {
                Class<?> clazz = null;
                clazz = Framework.getSystemClassLoader().loadClass(componentName);
                if (clazz != null) {
                    performLaunchChildActivity(container,key,intent);
                }
            } catch (ClassNotFoundException e) {
                Log.e("ActivityGroupDelegate",e.getCause().toString());
            }
        }

    }

若bundleName为空,用system Classloader获取class,执行performLaunchChildActivity

若bundleName不为空,根据bundleName获取到BundleImpl,执行performLaunchChildActivity

    private void performLaunchChildActivity(ViewGroup container,String key,Intent intent ){
        if(intent==null){
            Log.e("ActivityGroupDelegate","intent is null stop performLaunchChildActivity");
            return ;
        }
        mLocalActivityManager.startActivity(key,intent);
        container.addView(
                mLocalActivityManager.getActivity(key)
                        .getWindow().getDecorView(),
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT));
    }

performLaunchChildActivity方法很简单,ActivityManager启动Activity,然后将视图添加到ViewGroup

atlas组件化比较彻底,和360的框架一样,建立了自己的组件的体系,并兼容源生的Activity组件。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值