精华内容
下载资源
问答
  • Android Gradle Plugin 的下载,编译,debug1.1 下载安装 repo:mkdir ~/binPATH=~/bin:$PATHcurl ... ~/bin/repochmod a+x ~/bin/repo初始化并下载:mkdir android_gradle_pl...

    Android Gradle Plugin 的下载,编译,debug

    1.1 下载

    安装 repo:

    mkdir ~/bin

    PATH=~/bin:$PATH

    curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo

    chmod a+x ~/bin/repo

    初始化并下载:

    mkdir android_gradle_plugin

    cd android_gradle_plugin

    repo init -u https://android.googlesource.com/platform/manifest -b studio-master-dev

    repo sync

    1.2 编译发布

    插件代码在 tools/base:

    cd tools

    ./gradlew :publishAndroidGradleLocal

    版本号:

    在 tools/buildSrc/base/version.properties 中。

    1.3 debug

    Run/Debug Configurations 中创建一个 Remote;

    ./gradlew --no-daemon -Dorg.gradle.debug=true xxxTask;

    运行 debug。

    2 Android Gradle plugin 的具体流程

    2.1 流程

    先看一张经典的打包流程图:

    1efa89f68501

    image

    可以看到一共有以下几步:

    通过 aapt 打包 res 资源文件,生成 R.java、resources.arsc 和 res 文件(二进制 & 非二进制如 res/raw 和 pic 保持原样);

    处理 .aidl 文件,生成对应的 Java 接口文件;

    通过 Java Compiler 编译 R.java、Java 接口文件、Java 源文件,生成 .class 文件;

    通过 dex 命令,将 .class 文件和第三方库中的 .class 文件处理生成 classes.dex;

    通过 apkbuilder 工具,将 aapt 生成的 resources.arsc 和 res 文件、assets 文件和 classes.dex 一起打包生成 apk;

    通过 Jarsigner 工具,对上面的 apk 进行 debug 或 release 签名;

    通过 zipalign 工具,将签名后的 apk 进行对齐处理。

    再看一张现在官网给的构建流程图:

    1efa89f68501

    image

    编译器将您的源代码转换成 DEX(Dalvik Executable) 文件(其中包括运行在 Android 设备上的字节码),将所有其他内容转换成已编译资源。

    APK 打包器将 DEX 文件和已编译资源合并成单个 APK。不过,必须先签署 APK,才能将应用安装并部署到 Android 设备上。

    APK 打包器使用调试或发布密钥库签署您的 APK:

    如果您构建的是调试版本的应用(即专用于测试和分析的应用),打包器会使用调试密钥库签署您的应用。Android Studio 自动使用调试密钥库配置新项目。

    如果您构建的是打算向外发布的发布版本应用,打包器会使用发布密钥库签署您的应用。要创建发布密钥库,请阅读在 Android Studio 中签署您的应用

    在生成最终 APK 之前,打包器会使用 zipalign 工具对应用进行优化,减少其在设备上运行时的内存占用。

    2.2 构建

    有了初步的了解后,我们来看看 Android Gradle plugin 是如何实现构建流程的。

    com.android.application 和 com.android.library 是我们最熟悉的 android gradle plugin,我们可以在 tools/base/build-system/gradle-core/src/main/resources/META-INF/gradle-plugins 路径下找到。

    可以看到 com.android.application 插件对应的类是 com.android.build.gradle.AppPlugin,而 com.android.library 插件对应的类是 com.android.build.gradle.LibraryPlugin

    AppPlugin 类和 LibraryPlugin 类最终都是 extends BasePlugin、implements Plugin。

    从 apply() 方法开始执行,主要内容都在 basePluginApply() 方法中。

    private void basePluginApply(@NonNull Project project) {

    // 省略一些检查,运行管理,输出profile等代码,核心就三个方法

    configureProject();

    configureExtension();

    createTasks();

    }

    configureProject()

    private void configureProject() {

    // 以下代码有精简省略

    new ExtraModelInfo();

    new SdkHandler();

    // AndroidBuilder作用是process the build

    AndroidBuilder androidBuilder =

    new AndroidBuilder(

    project == project.getRootProject() ? project.getName() : project.getPath(),

    creator,

    // GradleProcessExecutor作用是execute external processes

    new GradleProcessExecutor(project),

    // GradleJavaProcessExecutor作用是execute external java processes

    new GradleJavaProcessExecutor(project),

    extraModelInfo.getSyncIssueHandler(),

    extraModelInfo.getMessageReceiver(),

    getLogger(),

    isVerbose());

    new DataBindingBuilder();

    // 最小版本

    GradlePluginUtils.enforceMinimumVersionsOfPlugins();

    // 依赖JavaBasePlugin插件

    project.getPlugins().apply(JavaBasePlugin.class);

    new DslScopeImpl();

    BuildCacheUtils.createBuildCacheIfEnabled();

    // plugin的全局变量

    new GlobalScope();

    // 添加描述

    project.getTasks()

    .getByName("assemble")

    .setDescription(

    "Assembles all variants of all applications and secondary packages.");

    // buildFinished后关闭释放操作

    gradle.addBuildListener(new BuildListener() {...});

    // 创建lint配置

    createLintClasspathConfiguration(project);

    }

    configureExtension()

    ……

    最后

    本文在开源项目:https://github.com/xieyuliang/Note-Android中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中……

    展开全文
  • 小米应用商店,是小米科技旗下米柚Android系统ROM中的一款安卓应用推荐软件。支持主流Android系统。立足于大量的小米手机用户,小米应用商店拥有巨大的流量,是中国最大的应用分发平台之一。今天就给大家说说如何在...

    说起小米手机,大家应该都不陌生,这几年小米手机火爆程度可谓是达到了万人空巷的程度,很多人熬夜排队抢小米。小米应用商店,是小米科技旗下米柚Android系统ROM中的一款安卓应用推荐软件。支持主流Android系统。立足于大量的小米手机用户,小米应用商店拥有巨大的流量,是中国最大的应用分发平台之一。今天就给大家说说如何在小米应用商店上传应用。

    一、创建应用

    小米应用商店按照符合Android标准的原则进行设计,使用包名(Package Name)作为应用的唯一标识。即:包名必须唯一,一个包名代表一个应用,不允许两个应用使用同样的包名。包名主要用于系统识别应用,几乎不会被最终用户看到。

    包名的命名规则:可以包含大写字母(A到Z)、小写字母(a到z)、数字和下划线,可以用点(英文句号)分隔,隔开的每一段都必须以字母开头。

    4b6a3b4e3d089e157f7807283ad3fad2.png

    二、上传安装包

    83b4952c9e281f59dcbb090d169b1cec.png

    三、完善资料

    关键词:关键词可以自定义输入100个字符,关键词之间用空格隔开。

    一句话简介:保持在17个汉字或34个字符(数字、英文、空格各占一个字符)之内,句末勿加标点。

    5e0989d7ddd8bbca761f0ef70b8eabf6.png

    四、截图

    手机尺寸截图:请上传至少 3 张图片,规格:720*1280 或 1080*1920,支持横屏或竖屏。

    61ad9e18418b1c3ab895426edb5e5dc5.png

    各位小伙伴注意了,小米应用商店中的关键词不拆分,不组词,不联想,也就是说,你设置的是多少词搜索的时候还是多少词。建议大家做优化的时候,选择最核心的,相关度高的词汇,资源有限不容浪费。

    展开全文
  • 前两天分析了Android系统的启动流程后,我们知道Android系统启动最终会走到Launcher,也就是我们所看见的”桌面“,app的启动是从用户点击桌面的icon开始的,当我们点击屏幕上的软件图标时,就可以打开这个软件,这...

    前两天分析了Android系统的启动流程后,我们知道Android系统启动最终会走到Launcher,也就是我们所看见的”桌面“,app的启动是从用户点击桌面的icon开始的,当我们点击屏幕上的软件图标时,就可以打开这个软件,这个过程看似也很简单,其实中间包含了很多的底层交互,接下来,我会从源码角度一步一步分析这个流程,看了不明白的,欢迎来打我。。

    启动流程一(Launcher)

    我们手机桌面——Launcher其实也是一个app,我们所看见的是它的一个activity,里面是一个RecyclerView包裹着所有的应用图标,图标中包含安装apk时解析的应用默认启动页等信息,在点击应用图标时,即将要启动的App和Launcher、AMS、Zygote都运行在不同进程中,所以他们之间的通信是通过binder去完成的,所以AMS是必不可少的。下面我们通过源码来看下:

    Launcher向AMS发送启动Activity

    当用户点击应用图标时,调用startActivitySafely方法:

    packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

    @Override
    public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
            @Nullable String sourceContainer) {
        if (!hasBeenResumed()) {
            
            addOnResumeCallback(() -> startActivitySafely(v, intent, item, sourceContainer));
            if (mOnDeferredActivityLaunchCallback != null) {
                mOnDeferredActivityLaunchCallback.run();
                mOnDeferredActivityLaunchCallback = null;
            }
            return true;
        }
    
        boolean success = super.startActivitySafely(v, intent, item, sourceContainer);
        if (success && v instanceof BubbleTextView) {
            
            BubbleTextView btv = (BubbleTextView) v;
            btv.setStayPressed(true);
            addOnResumeCallback(btv);
        }
        return success;
    }
    

    最终会走到startActivity中:

    @Override
    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }
    
    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
            && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
            if (TextUtils.equals(getPackageName(),
                                 intent.resolveActivity(getPackageManager()).getPackageName())) {
                // Apply Autofill restore mechanism on the started activity by startActivity()
                final IBinder token =
                    mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
                // Remove restore ability from current activity
                mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
                mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
                // Put restore token
                intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
                intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
            }
        }
        if (options != null) {
            //-1为requestCode表明不需要知道是否启动成功
            startActivityForResult(intent, -1, options);
        } else {
            startActivityForResult(intent, -1);
        }
    }
    

    调用startActivityForResult:进入看下

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
          
            ...
                
        } else {
            
          ...
        }
    }
    

    每个activity都持有一个Instrumentation对象,这个函数中传入了mMainThread.getApplicationThread(),它获取到的是ActivityThread的内部类ApplicationThread,这是一个Binder对象,之后AMS通过此对象与app通信

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
       ...
           
        try {
           
            int result = ActivityTaskManager.getService().startActivity(whoThread,
                    who.getBasePackageName(), who.getAttributionTag(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()), token,
                    target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
           ...
        }
        return null;
    }
    
    public static IActivityTaskManager getService() {
        return IActivityTaskManagerSingleton.get();
    }
    
    @UnsupportedAppUsage(trackingBug = 129726065)
    private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton = new Singleton<IActivityTaskManager>() {
        @Override
        protected IActivityTaskManager create() {
            final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
            return IActivityTaskManager.Stub.asInterface(b);
        }
    };
    

    这一步Launcher开始向AMS通信,IActivityTaskManager是一个代理AMS端Binder的对象,之后AMS开始startActivity。 到这里Launcher向AMS请求启动一个Activity的流程就结束了。

    启动流程二(AMS)

    AMS启动Activity

    现在流程走到了AMS进程中,上面通过代理调用了ATMS的startActivity方法:

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
                                   String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
                                   String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
                                   Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
                                   resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
                                   UserHandle.getCallingUserId());
    }
    
    @Override
    public int startActivityAsUser(IApplicationThread caller, String callingPackage,
                                   String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
                                   String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
                                   Bundle bOptions, int userId) {
        return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
                                   resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
                                   true /*validateIncomingUser*/);
    }
    
    private int startActivityAsUser(IApplicationThread caller, String callingPackage,
                                    @Nullable String callingFeatureId, Intent intent, String resolvedType,
                                    IBinder resultTo, String resultWho, int requestCode, int startFlags,
                                    ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
        assertPackageMatchesCallingUid(callingPackage);
        enforceNotIsolatedCaller("startActivityAsUser");
    
        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                                                              Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
    
        // TODO: Switch to user app stacks here.
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
            .setCaller(caller)
            .setCallingPackage(callingPackage)
            .setCallingFeatureId(callingFeatureId)
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setUserId(userId)
            .execute();
    
    }
    

    上面都是一些权限检查,通过一连串调用,走到了ActivityStarter里,调用了execute:

    int execute() {
        ...     
        res = executeRequest(mRequest);
        ...
    }
    
    private int executeRequest(Request request) {
        
        ...
            
         mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
                    request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
                    restrictedBgActivity, intentGrants);
    
           ...
               
            return mLastStartActivityResult;
        }
    

    接着调用了startActivityUnchecked方法,继续看这个方法:

    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, Task inTask,
                boolean restrictedBgActivity, NeededUriGrants intentGrants) {
        ...
            result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
       
        ...
    
        return result;
    }
    
    int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
            boolean restrictedBgActivity, NeededUriGrants intentGrants) {
        ...
            
        mRootWindowContainer.resumeFocusedStacksTopActivities(
                            mTargetStack, mStartActivity, mOptions);
        ...
    }
    
    boolean resumeFocusedStacksTopActivities(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
    
       ...
           
            if (!resumedOnDisplay) {
                final ActivityStack focusedStack = display.getFocusedStack();
                if (focusedStack != null) {
                    result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
                } else if (targetStack == null) {
                    result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
                            display.getDefaultTaskDisplayArea());
                }
            }
        }
    
        return result;
    }
    

    这里会调用resumeTopActivityUncheckedLocked:

    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
       
       ...
            result = resumeTopActivityInnerLocked(prev, options);
       ...
    
        return result;
    }
    

    继续走到resumeTopActivityInnerLocked:

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        ...
            if (mResumedActivity != null) {
           pausing |= startPausingLocked(userLeaving, false , next);
        }
        
            mStackSupervisor.startSpecificActivity(next, true, true);
        ...
    }
    

    startPausingLocked方法主要是通知Launcher进入Pause状态,在它进入这个状态后,在ActivityStackSupervisor的startSpecificActivity方法里判断新的app进程状态做出不同响应。一起看下这个方法:

    void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // 获取启动的activity进程信息
        final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);
    
        boolean knownToBeDead = false;
        //如果进程存在,并且进程中有线程存在,就启动一个同应用的activity
        if (wpc != null && wpc.hasThread()) {
            try {
                realStartActivityLocked(r, wpc, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
    
            // If a dead object exception was thrown -- fall through to
            // restart the application.
            knownToBeDead = true;
        }
    	
        //否则通过AMS向Zygote进程请求创建新进程
        r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
    
        final boolean isTop = andResume && r.isTopRunningActivity();
        mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
    }
    

    到这里就完成了Launcher和AMS的通信、以及AMS和zygote的通信,接下来创建要启动的app的线程,也就是ActivityThread。

    启动流程三(app)

    新的进程启动

    上面说到zygote启动新的进程时标记ActivityThread.main函数,在zygote创建好新进程后反射调用此方法,现在处于新的app进程中。

    public static void main(String[] args) {
       ...
           
    
        Looper.prepareMainLooper();
    
       ...
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
       
        ...
    
        Looper.loop();
    
    }
    
    private void attach(boolean system, long startSeq) {
    	...
            
            try {
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            
            ...
        }
    }
    
    @Override
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
           ...
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
           ...
        }
    }
    
    private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
                                            int pid, int callingUid, long startSeq) {
        ...
            //1
            thread.bindApplication(processName, appInfo, providerList,
                                   instr2.mClass,
                                   profilerInfo, instr2.mArguments,
                                   instr2.mWatcher,
                                   instr2.mUiAutomationConnection, testMode,
                                   mBinderTransactionTrackingEnabled, enableTrackAllocation,
                                   isRestrictedBackupMode || !normalMode, app.isPersistent(),
                                   new Configuration(app.getWindowProcessController().getConfiguration()),
                                   app.compat, getCommonServicesLocked(app.isolated),
                                   mCoreSettingsObserver.getCoreSettingsLocked(),
                                   buildSerial, autofillOptions, contentCaptureOptions,
                                   app.mDisabledCompatChanges);
    
        if (normalMode) {
            try {
                //2
                didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }
    }
    

    这里主要创建了Looper和ActivityThread对象,然后将当前应用ApplicationThread注册到AMS中,ApplicationThread是ActivityThread的内部类实现了IApplicationThread.Stub用此对象可跨进程通信。

    我们分两步看这个逻辑:

    1、在AMS绑定ApplicationThread时,发送了一个H.BIND_APPLICATION的Message,在Handler中处理该消息时调用了Application的onCreate方法。

    @Override
    public final void bindApplication(String processName, ApplicationInfo appInfo,
            ProviderInfoList providerList, ComponentName instrumentationName,
            ProfilerInfo profilerInfo, Bundle instrumentationArgs,
            IInstrumentationWatcher instrumentationWatcher,
            IUiAutomationConnection instrumentationUiConnection, int debugMode,
            boolean enableBinderTracking, boolean trackAllocation,
            boolean isRestrictedBackupMode, boolean persistent, Configuration config,
            CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
            String buildSerial, AutofillOptions autofillOptions,
            ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
    	...
            
        sendMessage(H.BIND_APPLICATION, data);
    }
    
    public void handleMessage(Message msg) {
        if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
        switch (msg.what) {
            case BIND_APPLICATION:
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                AppBindData data = (AppBindData)msg.obj;
                handleBindApplication(data);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                break;
                ...
        }
    }
    
    private void handleBindApplication(AppBindData data) {
        ...
         mInstrumentation.callApplicationOnCreate(app);
        ...
    }
    
    //Application.java
    public void onCreate() {
    }
    

    到这里为止,新的app线程已经启动并且绑定了Application

    创建activity

    2、在mAtmInternal的attachApplication中通过层层调用到ActivityStackSupervisor.realStartActivityLocked方法。

    boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
                                    boolean andResume, boolean checkConfig) throws RemoteException {
    
        ...
    
            // 创建activity启动事务
            final ClientTransaction clientTransaction = ClientTransaction.obtain(
            proc.getThread(), r.appToken);
    
        final DisplayContent dc = r.getDisplay().mDisplayContent;
     	clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                            System.identityHashCode(r), r.info,
                            mergedConfiguration.getGlobalConfiguration(),
                            mergedConfiguration.getOverrideConfiguration(), r.compat,
                            r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
                            r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
                            dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
                            r.assistToken, r.createFixedRotationAdjustmentsIfNeeded()));
    
        // Set desired final state.
        final ActivityLifecycleItem lifecycleItem;
        if (andResume) {
            lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
        } else {
            lifecycleItem = PauseActivityItem.obtain();
        }
        clientTransaction.setLifecycleStateRequest(lifecycleItem);
    
        //执行clientTransaction
        mService.getLifecycleManager().scheduleTransaction(clientTransaction);
        ...
    }
    
    

    ClientTransaction管理了activity的启动信息,通过ClientLifecycleManager执行,调用

    scheduleTransaction方法,看下这个方法:

    void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        final IApplicationThread client = transaction.getClient();
        transaction.schedule();
        if (!(client instanceof Binder)) {
            transaction.recycle();
        }
    }
    

    调用了ClientTransaction类的schedule方法:

    public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this);
    }
    

    mClient是一个IApplicationThread接口,上面我们也分析到,它的实现是ApplicationThread,而ApplicationThread是ActivityThread的内部类,我们进去看下:

    @Override
    public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        ActivityThread.this.scheduleTransaction(transaction);
    }
    

    ApplicationThread的scheduleTransaction方法其实是调用了ActivityThread的同名方法。而ActivityThread自身并没有定义这个方法,而是继承自父类ClientTransactionHandler:

    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }
    

    scheduleTransaction方法中发送了EXECUTE_TRANSACTION消息给ActivityThread的H类处理,H肯定是继承自Handler了,来看下:

    class H extends Handler {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                    ...
                    case EXECUTE_TRANSACTION:
                    final ClientTransaction transaction = (ClientTransaction) msg.obj;
                    mTransactionExecutor.execute(transaction);
                    if (isSystem()) {
                        transaction.recycle();
                    }
                    break;
                    ...
            }
        }
    }
    

    通过handleMessage来处理这个消息,里面又调用了TransactionExecutor的execute方法:

    public void execute(ClientTransaction transaction) {
        ...
        executeCallbacks(transaction);
        executeLifecycleState(transaction);
        mPendingActions.clear();
    
    }
    
    public void executeCallbacks(ClientTransaction transaction) {
           final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
           ...
    
            final int size = callbacks.size();
            for (int i = 0; i < size; ++i) {
                final ClientTransactionItem item = callbacks.get(i); 
                ...
                item.execute(mTransactionHandler, token, mPendingActions);  
            }
    }
    
     private void executeLifecycleState(ClientTransaction transaction) {
            final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
    
         //生命周期的过渡
            cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);
    
            lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
            lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
     }
    

    这里分别调用了executeCallbacks和executeLifecycleState,也就是事务Callback和LifecycleState的execute方法,这里的Callback和LifecycleState是在ActivityStackSupervisor的realStartActivityLocked流程创建的,分别对应的是LaunchActivityItem和ResumeActivityItem。来看下这两个execute方法:

    //LaunchActivityItem.java
        
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
       ...
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        
    }
    
    //ResumeActivityItem.java
    
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        ...
        client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
                "RESUME_ACTIVITY");
    
    }
    

    可以看到这两个execute方法里都是调用了ClientTransactionHandler来处理activity的,而

    ClientTransactionHandler是抽象类,最终又回到了ActivityThread类中,看下:

    public Activity handleLaunchActivity(ActivityClientRecord r,
         
    	...
                                         
        final Activity a = performLaunchActivity(r, customIntent);
    
        return a;
    }
    
        private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            //获取activity信息
            ActivityInfo aInfo = r.activityInfo;
           
            //拿到启动activity的组件名
            ComponentName component = r.intent.getComponent();
            ...
                
            ContextImpl appContext = createBaseContextForActivity(r);
            Activity activity = null;
            try {
                java.lang.ClassLoader cl = appContext.getClassLoader();
                activity = mInstrumentation.newActivity(
                        cl, component.getClassName(), r.intent);
            }
            ...
               
    
            try {
                Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    
               ...
                   
                    activity.attach(appContext, this, getInstrumentation(), r.token,
                            r.ident, app, r.intent, r.activityInfo, title, r.parent,
                            r.embeddedID, r.lastNonConfigurationInstances, config,
                            r.referrer, r.voiceInteractor, window, r.configCallback,
                            r.assistToken);
    
                    int theme = r.activityInfo.getThemeResource();
                    if (theme != 0) {
                        activity.setTheme(theme);
                    }
    
                ...
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnCreate(activity, r.state);
                    }
                   
                ...
            return activity;
        }
    

    梳理下这个方法做了哪些事情:

    • 创建启动activity的上下文环境
    • 通过Instrumentation的newActivity方法,以反射形式创建activity实例
    • 如果Application不存在的话会创建Application并调用Application的onCreate方法
    • 初始化activity,通过Activity的attach方法,实例化Window对象,并实现Activity和Window相关联
    • 通过Instrumentation调用activity的onCreate方法

    与handleLaunchActivity类似的,handleResumeActivity则是调用了performResumeActivity方法。其大体上依次做了:

    • 如果需要,调用待Resume Activity的onNewIntent、onActivityResult回调;
    • 调用Activity的performResume方法,其中调用了onResume回调;

    这样,app就启动完成了。

    最后,给大家看下整体的流程图(其实是从网上盗的图…哈哈)
    在这里插入图片描述

    总结

    通过上面的分析,我们基本把app启动流程走完了,看起来比较复杂,其实通过整体分析,还是能走通的,遇到流程不通时,也可以debug。

    • 点击图标,Launcher向AMS请求启动app
    • AMS收到请求后,记录app的信息,并告知Launcher进入pause状态
    • Launcher进入pause状态后,告知AMS
    • AMS检测新的app进程时候已经启动,否则通过Zygote创建新的进程并启动ActivityThread的main方法
    • 进程创建好后,调用上面的ActivityThread.main()
    • ActivityThread中H处理需要启动Activity的请求消息

    本人能力有限,在分析过程中,代码有所删减,如果文章中有写得不对的地方,欢迎在留言区留言大家一起讨论,共同学习进步。如果觉得我的文章给予你帮助,也请给我一个喜欢和关注。

    展开全文
  • 一、APP与Web测试的异同 1、相同点:流程方面相同,都要经过计划,方案,测试分析,用例,环境搭建,测试执行,报告,总结等         都要进行功能测试,性能测试,兼容性测试,安全测试,安装/...

    一、APP与Web测试的异同
    1、相同点:流程方面相同,都要经过计划,方案,测试分析,用例,环境搭建,测试执行,报告,总结等
            都要进行功能测试,性能测试,兼容性测试,安全测试,安装/升级/卸载测试
    2、不同点1:兼容性方面
        WEB的兼容性主要关注:服务器的操作系统,数据库的类型,客户端的操作系统,客户端的浏览器
        APP的兼容性主要关注:不同品牌及型号,操作系统类型及版本,屏幕大小,分辨率
         不同点2:性能方面
        WEB系统的性能测试只需要测试服务端的性能
        APP系统的性能测试包括服务端和终端的性能
         不同点3:安装方面
        WEB系统的安装主要在服务器端
        APP系统的安装包括服务端和终端
         其他不同点:
        APP专项测试相关

    二、APP专项测试
    1、APP测试的准备
         移动观象台 http://mi.talkingdata.com/index.html
        确定APP的设备(品牌、型号、尺寸、屏幕分辨率)
        确定APP的版本及操作系统类型(iOS和Android)
        用表格记录APP的设备和版本
    2、网络测试:2G,3G,4G,Wifi,移动,联通,电信,弱网,强网
           不同网络下能正常工作,网络中断,连接,切换
    3、多任务处理,切换及意外情况处理
        正常打开被测APP
     
        运行APP的功能
        突然被其他应用打断(意外,短信、电话、通知)
      
        切换到该应用、或者、忽略该应用
      
        被测APP能够继续之前的操作,不发生`ANR`或者`Crash`
    4、手势 (长按屏幕,上下、左右滑动,双手指捏合、放大放小)
    5、消息通知及显示
    6、使用高内存的处理 (App对于读取大量图片、视频等进行高内存占用操作的处理能力)
    7、支持的文件格式
    8、APP的用户体验(横屏,字体大小设置以及美观,遵循iOS和Android的设计规范)
    9、APP响应不同的设备用户界面
    10、APP的消息显示和通知显示 (锁屏的通知,下拉通知栏的通知,应用程序消息栏)
    11、APP能否及时显示和同步数据(Web端 + PC端 + APP端 同步消息及数据)
    12、安装、升级及卸载测试
    13、操作系统升级之后能否访问APP
    14、应用召唤
    15、多台设备登录

    三、APP测试环境 [模拟器的使用]
    1、安装jdk,配置环境变量
    2、解压android sdk,解压之后,打开文件夹
    3、运行 AVD Manager.exe 创建模拟器
    4、如果需要其他版本的android模拟器,则使用 SDK Manager.exe 自行下载

    四、ADB命令 [以下命令需要掌握,具体请参考adb命令文档]
    1、adb devices
    2、adb shell
    3、adb -s 模拟器编号 命令
    4、adb install ***.apk
    5、adb install -r ***.apk
    6、adb uninstall 应用程序包名  
    7、adb pull
    8、adb push
    9、adb logcat

    五、Monkey工具
    1、为com.amaker.mp执行500次monkey,反馈级别为一级
      adb shell monkey -p com.amaker.mp -v 500
    2、为com.amaker.mp执行500次monkey,反馈级别为一级,并将结果重定向到文件中
      adb shell monkey -p com.amaker.mp -v 500 > d:\monkey.txt
    3、为事件加延时操作,固定延时300ms,注意,如果要在报告中显示延时,则需要反馈级别为二级,即 -v -v
      adb shell monkey -p com.amaker.mp --throttle 300 -v -v 500 > d:\monkey.txt
    4、为事件加随机延时,每次延时在0~400ms之间
      adb shell monkey -p com.amaker.mp --throttle 400 --randomize--throttle -v -v 500 > d:\monkey1.txt
    5、忽略monkey运行时出现的崩溃和应用程序无响应,当出现时,monkey运行不终止,直到所有次数全部运行完炎止
      adb shell monkey -p com.amaker.mp --throttle 400 --randomize-throttle --ignore-crashes --ignore-timeouts -v -v 500 > d:\monkey1.txt
    6、忽略其他异常,如monkey本身异常,证书异常等
      adb shell monkey -p com.amaker.mp --throttle 400 --randomize-throttle --ignore-crashes --ignore-timeouts --ignore-native-crashes --ignore-security-exceptions --monitor-native-crashes -v -v -v 500 > d:\monkey1.txt
    7、-s 随机数seed值
      adb shell monkey -p com.amaker.mp -s 315 --throttle 400 --randomize-throttle --ignore-crashes --ignore-timeouts --ignore-native-crashes --ignore-security-exceptions --monitor-native-crashes -v -v -v 500 > d:\monkey1.txt
    8、定义事件百分比
      如果百分比不足100,剩余的则自动按比例分配
      adb shell monkey -p com.amaker.mp -s 315 --pct-touch 40 --throttle 400 --randomize-throttle --ignore-crashes --ignore-timeouts --ignore-native-crashes --ignore-security-exceptions --monitor-native-crashes -v -v -v 500 > d:\monkey1.txt
      如果百分比正好为100,则按定义的百分比运行
      adb shell monkey -p com.amaker.mp -s 315 --pct-touch 40 --pct-motion 60 --throttle 400 --randomize-throttle --ignore-crashes --ignore-timeouts --ignore-native-crashes --ignore-security-exceptions --monitor-native-crashes -v -v -v 500 > d:\monkey1.txt
      如果百分比超过100,则会报错,不能运行monkey
    Monkey结果分析:
      查找ANR问题与崩溃问题:查 ANR, crash, exception, error
      ANR日志的位置:/data/anr -> traces.txt

    六、易测EasyTest
    https://easytest.taobao.com

    七、Testin云平台
    https://www.testin.cn

    八、手机如何连接电脑,使用adb访问手机?
    1、打开手机的开发者工具
    2、打开手机的USB调试功能
    3、如果做了以上两项后,adb还找不到手机设备,请参考此处操作https://jingyan.baidu.com/album/ce09321b5b76642bff858f31.html?picindex=2

    展开全文
  • APP测试基本流程

    2021-07-14 21:00:11
    之前发过app测试的一些想法,我这里还有一些app测试的具体指标。部分是可以百度的到的,部分是自己总结的。 一、 测试周期 测试周期一般为两周,根据项目情况以及版本质量可适当缩短或延长测试时间。正式测试前先...
  • 如何开发一个安卓app安卓app开发流程包含哪些步骤呢?现在手机app开发可以分为两种模式:编程开发、免编程制作。下面分别为大家介绍两者的开发流程第一:编程开发1、需求沟通在app开发前,需要对app进行详细的分析...
  • 背景技术:在目前的软硬件环境下,androidapp(应用程序软件)是必须通过安装新版本才能完成版本更新和异常修复。这样的方式主要体现在;1、当业务发生变更时,app开发商会重新开发新的版本,这就需要用户频繁的升级...
  • 针对app测试 过程和重点关注内容,做以下梳理和总结。1 、首先是测试资源确认及准备(1 ) 产品需求文档、产品原型图、接口说明文档以及设计说明文档等应齐全;(2 ) 测试设备及工具的准备: ios 和 andriod 不同...
  • 手机App测试流程

    2021-01-21 18:22:10
    增加新的功能来优化自己的产品,每一个手机软件的版本的回归也好自动化也好,和电脑是不一样的,电脑只能看到最新版本,手机APP是不能保证所有用户都用最新版本的,所以手机APP测试要更关注老版本的兼容和新功能的...
  • 手机APP测试,主要针对的是android和ios两大主流操作系统,主要考虑的就是功能性、兼容性、稳定性、易用性(也就是人机交互)、性能。 手机APP测试前的准备: 1.使用同类型的产品,不仅仅是使用,应该是测试同类型的...
  • (一)在系统的app启动前 1.机器Poweron(芯片烧录的时候已经设置好的,会根据硬件以及GPU的设置来判断系统启动是在U盘还是sdcard或者内置flash中,去引导uboot) 2.bootloader(它是嵌入式系统上电后加载的第一段代码...
  • 原标题:Android App自动化测试基本流程测试思路(一)来源:https://www.testwo.comAPP的自动化测试有多重要,我就不赘述了,今天我们先来聊一聊Android App自动化测试的基本流程和思路。1、需求分析测试都是基于...
  • 1 APP测试基本流程 1.1预估测试周期 测试周期可按项目的开发周期来确定测试时间,一般测试时间为两周(即10个工作日,一人份工作量),根据项目情况以及版本质量可适当缩短或延长测试时间。正式测试前先向主管...
  • 在开始APP安卓端渗透测试时,根据需要制定步骤,并向委托方详细说明需要使用的工具、方法等。具体操作时,会把渗透测试分成三个部分和阶段,不同的角度使区别的方法有所不同,例如在理论上把渗透测试分为准备阶段、...
  • Android APP存活检测

    2021-06-07 09:18:17
    稍微深入了解过Android的开发者都知道,Android中每个APP的中的所有组件的生命周期状态都是由ActivityManagerService(简称:AMS)进程来维护的,所以当某个APP被kill或意外crash时,AMS进程会第一时间维护APP的组件。...
  • App测试基本流程

    2021-03-24 21:58:03
    App测试基本流程详解(汇总整理) 前言  看过许多大神对APP测试的理解,博主总结了一下我们平时测试APP应该注意的一些测试点并结合大神的理解,总结出这篇文章。 一.测试周期  测试周期一般为两周,根据项目情况...
  • app的启动方式 App启动有三种状态,每种状态都会影响App对用户可感知的时间:冷启动,热启动和温启动。 注意:在冷启动中,应用从头开始启动。在其他状态下,系统需要将后台运行中的应用带入前台。建议您始终在假定...
  • 为什么要用离线打包呢,因为是开发安卓第三方插件,主要用的是Android Stuido,所以把5+APP项目导到Android studio里来,方便开发和测试。 其实还有一个原因,涉及到的第三方插件用到了系统级权限,要用platform.pk...
  • 根据软件说明或用户需求验证App的各个功能实现,实际测试过程一般都是根据功能测试用例来执行。测试覆盖率基本上都是有测试用例主导,也就是说在功能测试部分,是检验测试用例是否有效以及完整的,也就导致另外一个...
  • ODM项目为了测试平台稳定性,会下载大量第三方app进行冷、热启动的测试,并生成测试报告。 根据测试结果可用于暴露平台性能上的一些缺陷。 实现:pythn+adb 以下分享源码实现过程 # !/usr/bin/python # -*- ...
  • 简单说下手机控件银联支付的流程: 概括一下就是,app这边将购买的商品信息提交给app后台,app后台接收到购买信息之后,将信息提交给银联后台,银联接收到支付信息给app后台返回一个交易流水号(也就是app需要的tn号...
  • 通过本篇教程,可以学习到ios证书申请和打包ipa测试上架的完整流程,中途可能会遇到一些报错,一般在教程对常见错误都有解释,仔细看看,不清楚可以联系技术支持或者加群提问。 也录制了视频教程,想看视频教程的,...
  • 移动安全-Android APP敏感信息测试

    千次阅读 2021-01-24 02:26:46
    文章目录移动金融APP备案Android APP数据存储sdcard 文件SQLite数据库ContentProvidersharedPreferencesAPK客户端敏感信息测试Logcat 运行日志SQLite 数据库sharedPreferences其他本地文件的检查Genymotion模拟器...
  • Android App常见的异常可分为三种:ANR,Crash及OOM。当异常发生时如何正确的获取日志定位问题非常重要。本文针对这三种异常分别给出了处理建议,并提供了一些日志收集框架及日志上传的思路。ANRANR(Application No ...
  • 将Flutter Android app 发布Google Play(谷歌应用商店)流程 一、首先就是要做到科学! 二、打开google play官网,注册谷歌账号 三、打开谷歌开发者站点https://play.google.com/apps/publish/signup/创建你的App...
  • APP测试流程

    2021-09-06 09:52:01
    手机端 app测试流程和方法:一般原生 App都使用系统的方法来完成开发和提交。因为 App框架是基于本地+H5的,H5负责显示和交互。由 Android和 iOS本机预定义一些统一的界面,h5直接调用,从而免除复杂的兼容性判断,...
  • App拉起另一个App的使用场景: 1.使用一个管理型App统一进行app的管理。如:可以应用于登录,然后拉起对应App,如未安装则进行安装。 2. 对于智能硬件app,很多运行环境处于无网络情况,出现异常及崩溃后log无法采集...
  • 一、APP版本更新通知流程图如下:二、测试注意点:1、Android更新直接下载APK,IOS引导至APP Store更新页面;强制更新------只有“立即更新”1、一般“强制更新”的机制不常用,除非涉及到APP的紧急且致命缺陷的修复...
  • 主要学的Android开发,所以投的岗位都是Android开发工程师。投了知乎,内推了阿里蘑菇街腾讯百度网易。腾讯百度都没有收到面试,知乎Skype面试,蘑菇街阿里电话面试,网易现场面。知乎二面被拒,蘑菇街阿里一面被拒...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 60,649
精华内容 24,259
关键字:

安卓app测试流程