中國大學 MOOC Android 客戶端開發提效之頁面信息

本文主要描述了怎麼樣提升一個客戶端開發排查和定位的效率,而且動手寫了一個小工具的實踐和思考,以及團隊中其餘合做者可以提升了定位問題效率,驗證功能是否準確的效率。前端

做者/馬傑 中國大學 MOOC 團隊android

編輯/劉振宇web

1、前言

中國大學 MOOC 是由網易與高教社攜手推出的在線教育平臺,承接教育部國家精品開放課程任務,向大衆提供中國知名高校的 MOOC 課程。目前,不管是課程數量、質量仍是社會影響力,中國大學 MOOC 都已成爲全球領先的中文慕課平臺。shell

在平常的 Android 開發中,咱們常常會遇到如下的一些問題:測試、運營、產品同窗跑過來講這個頁面出了問題,趕忙看下。這時候客戶端開發同窗就須要趕忙定位到具體的某個頁面。windows

據觀察,大部分的狀況下對於一個突發頁面的問題定位,或者業務方想讓開發者確認這個頁面的業務邏輯的時候,客戶端開發者,每每須要花費比較長的時間去給業務方答覆。若是近期業務可能還能記得,可是客戶端的頁面比較多,想要快速定位到具體業務頁面,那麼就須要花更多的時間去找相關的頁面。網絡

因此本文的想法是怎麼快速找到對應的頁面,幫助開發快速的進入業務代碼,快速的回覆業務方提出的問題。app

2、方案實施

在探討方案的時候,咱們須要對比目前有哪些方案,對比以後再選擇一種更加有效的方法。ide

2.1 解決問題的經常使用方式

在 Android 開發中解決上述提供的問題,經常使用的有如下 3 種方式:工具

  • 打開 Android studio,靠着源碼記憶,文案記憶去搜索;
  • 使用 adb 命令來過濾當前的 activity;
// windows
adb shell dumpsys window windows | Select-String -Pattern 'mCurrentFocus|mFocusedApp|mLastOpeningApp|mObscuringWindow'
  
// Mac
adb shell dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp|mLastOpeningApp'
  • 全局搜索關鍵文案。

上面 3 種方式是可以解決問題,但從時間效率上分析,能夠估算一下每一種方式大概須要多長時間:佈局

第一種,按照我的經驗,熟悉項目代碼的同窗最快也要幾十秒左右,慢的話 10 幾分鐘;

第二種,使用 adb 可以幾秒就定位到頁面,可是須要記住命令,或者提早設置命令快捷方式;

第三種,若是有不少相同文案,須要多搜索幾遍,時間也多是10幾秒到1分鐘不等。

全部上面幾種方式得出的時間效率就是幾秒到幾分鐘不等,並且基本都是須要代碼或者 adb 的開發工具,依賴於開發環境。

既然須要花的時間也很多,那麼是否是應該作一個工具來提高更快的定位速度,提高定位效率呢?

2.2 更加高效的方法

其實思路很簡單,就是寫一個開發的SDK,用來實時關注當前的頁面信息。這個頁面信息主要包含以下的信息:

  1. 當前 Activity 是哪一個?
  2. 當前的 Fragment 是哪一個?
  3. 當前頁面的參數傳遞,如:intent 中的各類參數是什麼?

效果圖以下

從上面信息就可以很快的定位到當前的頁面;當一個頁面的深度到很是深的時候,這樣的小工具就特別好用;最快速度只要幾秒就能快速定位到頁面,效率提高快幾十倍不止,並且可以當着測試和產品的面,可以把當前關鍵的參數給他看,如:xxxId、埋點信息等。

2.3 主要實現原理

上面的小工具,主要的工做是得到當前的Activity。得到當前Activity的方式主要有如下幾種方式:

  1. 經過 RunningTaskInfo的 topActivity,該方法在後續的一些版本已經被禁用
  2. 手寫代碼管理Activity,這個方法比較粗暴,維護比較麻煩;
  3. 經過反射 ActivityThread得到 currentActivityThread 從 mActivities 中查詢得到;
  4. 使用AccessibilityService 這個輔助功能,這個方法得到的信息比較少;
  5. 經過 ActivityLifecycleCallback 監聽來得到。

通過對比,選擇使用AccessibilityServiceActivityLifecycleCallback 這2種方式去嘗試。如下就簡單的說下這2種方法的實現,並進行兩者之間的對比以及最後作出的選擇。

2.3.1 ActivityLifecycleCallback 方式

private static Activity topActivity;
        @Override
    public void onActivityResumed(Activity activity) {
        topActivity = activity;
    }

是否是很簡單?爲了不內存泄漏,能夠在 onDestroy 的時候把 topActivity 設置成 null。這種方式簡單快速,不須要申請權限。

2.3.2 AccessibilityService 方式

  • 繼承 AccessibilityService
@Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        Log.d(TAG, "onAccessibilityEvent");
        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            if (event.getPackageName() != null && event.getClassName() != null) {
                ComponentName componentName = new ComponentName(
                        event.getPackageName().toString(),
                        event.getClassName().toString()
                );
                ActivityInfo activityInfo = tryGetActivity(componentName);
                boolean isActivity = activityInfo != null;
                if (isActivity) {
                    Log.d(TAG, "CurentActivity " + componentName.flattenToShortString());
                    Log.d(TAG, "CurentActivity " + event.getPackageName().toString());
                }
            }
        }
    }
private ActivityInfo tryGetActivity(ComponentName componentName) {
        try {
            return getPackageManager().getActivityInfo(componentName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            return null;
        }
    }
  • manifest 配置
<service
            android:name=".WindowChangeDetectingService"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService"/>
            </intent-filter>
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibilityservice"/>
        </service>
  • 須要 res/xm/accessibilityservice.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<!-- These options MUST be specified here in order for the events to be received on first
 start in Android 4.1.1 -->
<accessibility-service
    xmlns:tools="http://schemas.android.com/tools"
    android:accessibilityEventTypes="typeWindowStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagIncludeNotImportantViews"
    android:canRetrieveWindowContent="true"
    android:description="@string/accessibility_service_description"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:ignore="UnusedAttribute"/>

2.3.3 2種方式的對比

實現角度對比,使用 ActivityLifecycleCallback 比 AccessibilityService 更加簡單。可是 AccessibilityService 有個優點就是能夠不用集成到本身的 app 裏面,能夠獨立運行,能夠查看全部的當前頁面是屬於哪一個 Activity,能夠跨進程使用。使用 ActivityLifecycleCallback 必需要集成到本身的 app 中。

實踐過程中,其實咱們不僅是想得到當前的 Activity ,咱們還想知道當前的 Activity 中有哪些當前的 fragment, 當前的 Activity 從上一個 Activity 中得到了哪些參數,當前的fragment 中有哪些參數等細節信息,那麼只能集成到 app 中去的時候纔會比較容易得到。因此最後選擇了使用 ActivityLifecycleCallback 的方式。

2.3.4 頁面更詳細的信息

通常頁面上的信息開發,簡單一點的就是一個 Activity 而後簡單佈局;複雜一點的基本都是 Activity + (ViewPager)Adatper + fragment, 有時候 fragment 裏面還會有 ViewPager 裝載着 fragment, 對於不熟悉代碼的人找對應的業務邏輯頁面和代碼,仍是須要花費很多時間的。因此頁面信息 fragment 也很重要。

topActivity.getIntent().getExtras();// 得到 activity 的頁面參數
topActivity.getSupportFragmentManager().getFragments(); // 得到 activity 一級中的 fragments
fragment.getChildFragmentManager().getFragments();// 對應 fragment 中的 fragments
fragment.getArguments() // 得到 fragment的頁面參數

3、 提升效率舉例

關於頁面信息採集,在這裏列舉了幾個使用場景,來證實效率獲得了提升:

  1. 對於客戶端開發者,可以快速的定位到當前出錯的頁面,特別是剛來的開發,或者不熟悉這塊業務的,或者業務頁面深度比較深的時候;
  2. 頁面核心參數的確認。好比詳情頁面須要一些 id,這些詳細參數就不須要客戶端同事打斷點的方式去獲取,運營和測試本身能夠去查看;
  3. 精品課和雲課堂集成的時候,可以讓測試同窗快速的區分哪一個是精品課裏面的頁面,哪一個是雲課堂裏面的頁面,這樣方便測試知道當前頁面是屬於哪一個業務端的;(這個場景是網易內部融合項目)
  4. 頁面全鏈路參數傳遞驗證場景。好比:首頁點擊須要傳遞轉化率的參數一直傳遞到下單頁面,平時都是開發本身驗證,有這個工具後,產品也能在提測後,從測試包上本身查看驗證。

4、 頁面信息其餘想法

關於頁面信息場景加強,如下幾種頁面信息方式,認爲能夠進行擴充的:

  1. 能夠得到 RecyclerView 中的 adapter;(有不少佈局邏輯,放到了 adapter 裏面的 ViewHolder)
  2. webview 當前信息的監控;(前端同事調試)
  3. 網絡看板的監控;(當前頁面的網絡請求信息)
  4. 不鏈接電腦 Logcat 日誌查看看板;(不用鏈接電腦,得到 adb 信息)
  5. 參考線,界面元素位置,對應元素的顏色。(UI 走查的驗證)

以上的幾點,主要是按照自身 app 的狀況去判斷是否須要實現,判斷哪些實現性價比比較高。目前已經實現的,基本都是我的認爲性價比是比較高的東西。

5、 總結

當咱們碰見一個問題的時候,首先思考這個問題是否是本身比較難受的點,而後觀察其餘人是否有相似的狀況。這個問題經常使用的解決方案什麼?有沒有工具方法去替代?若是沒有,可不能夠用比較低的成本去製造一個工具?最後來提高本身的效率,這個工具若是可以幫助其餘人,那麼能效就更加好了。

-END-

相關文章
相關標籤/搜索