仿QQ獲取設備中APK并分享

onau7184 8年前發布 | 19K 次閱讀 Android開發 移動開發 QQ APK Android

我和郭霖

13年,郭霖開始寫技術博客。我在CSDN的博客頻道逛著玩,剛好看到他的文章,于是點擊進去閱讀。看完之后最大的感受就是:代碼整齊,技術深厚;文章寫得圖文并茂,有條有理。從那時起,我就成了郭霖的一個粉絲,每周四早晨都等著看他的更新。誠實地說:沒有腦殘地追過星,但這么實在地喜歡看一個人寫的技術博客,這還是頭一回。其實,從他每篇文章的點擊量和評論數也可以看出:大家對郭霖非常的認可。他也常出現在CSDN的首頁,有時還無恥地連續出現幾次。去年,部門經理交給我十幾個大學畢業生,老大問我:他們適合從哪里學起?我基本沒有過腦子地說:每個人買一本《第一行代碼》,快去吧,京西十一點前下單下午就能送到。從那以后,部門來的新手,公司都會讓他們照著這本書夯實一下基礎。

嗯哼,期待郭大嬸帶給我們更多的分享。

書歸正傳。

前幾天看到同事里有一個界面絢麗的應用,覺得有點意思,就讓他把APK發給我,我想反編譯看看里面的代碼。結果,這哥們在手機里找了好一陣子,最后給我說:手機沒有root,找不到APK文件在哪里。我再讓他試試其他機子,結果都差不多:要不然找起來很麻煩,要不然根本都找不到。這時,測試的妹子說:手機QQ有這個功能。我打開手機QQ一看,果然有,平時都沒有注意到啊。

這里寫圖片描述

這個功能點稍作總結:
- 每個item包括:應用的icon,名字,安裝文件的大小,最后更新時間
- 點擊item分享其對應的APK文件

看到這里,心里怪癢癢的,我們也能做這么個類似的東西么?
能的!必須能!否則在測試的妹子面前怎么能抬起頭!?

我們先獲取手機中已經安裝的應用:

List<PackageInfo> packageInfoList = mPackageManager.getInstalledPackages(0);

這些應用已經都躺在這里了,我們現在就一步一步地來找出每個應用的相關信息。

(1) 獲取應用的名稱

    /** * 獲取應用的名稱 */
   public String getApplicationName(String packageName,PackageManager packageManager) {
        String applicationName=null;
        try {
            ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
            applicationName = (String) packageManager.getApplicationLabel(applicationInfo);
        } catch (PackageManager.NameNotFoundException e) {

        }
        return applicationName;
    }

嗯哼,這個不難,剛上路的小司機也可以輕松的搞定。

(2) 獲取應用的icon

應用的名字我們容易獲得,那它的icon又在哪里呢?
既然獲得應用名字用的是:

packageManager.getApplicationLabel(applicationInfo);

那么是不是有類似的getApplicationIcon方法呢?趕緊試著敲一下代碼,AS提示果然有我們想要的東西:

packageManager.getApplicationIcon(ApplicationInfo info)

嗯哼,真愉快,我們猜對啦。把代碼運行起來瞅瞅,我的華為手機沒有問題。換個三星試試,也對呢;再用HTC跑跑,獲取到的居然是個小綠人——系統默認的圖標!再從測試妹子那里拿個小米過來,一樣啊,沒有正確獲取到應用對應的圖標。

不開心了,喝口水,默默地打開度娘找答案。看到這樣的方式:

//.........
        Class pkgParserCls = Class.forName(PATH_PackageParser);
        Class[] typeArgs = new Class[1];
        typeArgs[0] = String.class;
        Constructor pkgParserCt = pkgParserCls.getConstructor(typeArgs);
        Object[] valueArgs = new Object[1];
        valueArgs[0] = apkPath;
        Object pkgParser = pkgParserCt.newInstance(valueArgs);
//.........

居然用的是反射,復雜就不說了而且還影響效率。所以,在不得已的情況下還是不要這么做了。看來想通過PackageManager獲取應用的Icon是不行了,那就換個角度從PackageInfo入手試試,看到一個字段:

public ApplicationInfo applicationInfo;

官方文檔的解釋是: Information collected from the application。也就是說這個字段包含了App的眾多信息。所以,接著看ApplicationInfo里面有啥東西,掃了一眼,看到一個東西:

//Retrieve the current graphical icon associated with this item.
 public Drawable loadIcon(PackageManager pm) {
        return pm.loadItemIcon(this, getApplicationInfo());
    }

利用該方法才可以避免在某些機型上無法獲取應用的icon的bug。手邊的機子試了一遍,都沒問題。這個小問題解決了,就接著往下走。

(3) 獲取應用的最后更新時間
這個也挺容易的,PackageInfo中有相應的字段:

public long lastUpdateTime;

當然這個值是個毫秒值,需要利用SimpleDateFormat將其轉換成項目需要的日期格式。
有些情況下還需要獲取應用的第一次安裝時間,PackageInfo中也有相應的字段:

public long firstInstallTime;

同理,也需要對其進行格式化。

(4) 獲取Apk文件大小
要獲取Apk文件大小,首先得找到Apk文件。就像我想周末和妹子去逛街,前提是我得有個妹子啊(打住,不說了,眼淚滴到鍵盤上了)
但是它到底在哪里呢?幻想著利用PackageManager是不行的,它根本沒有類似于getApplicationApk( )的方法。
那怎么辦呢?喔,還記得前面提到的PackageInfo中的ApplicationInfo字段么?我們繼續去里面找,看看有沒有啥收獲,在源碼501行發現一個字段:

public String sourceDir;

官方文檔是這么描述的:Full path to the base APK for this application。嗯哼,bingo!找到了就是它,它代表了APK文件的完整路徑。文件路徑已經拿到了,啥都好辦了(就像知道了妹子住哪里,就可以……..)

File apkFile = new File(packageInfo.applicationInfo.sourceDir);

我們將該路徑封裝成一個文件,再獲取它的大小即可.

apkFile.length() / 1024 / 1024

在此處將文件大小轉換成了MB單位,比如豌豆莢的APK文件為6.46MB

好了,想要的東西我們都找到了,我們用一個ListView把每個APK的相關信息作為item展示出來就行了。有個小問題請注意:獲取手機中APK信息,這是一個耗時的過程,所以我們要在子線程中來做這個事情。

好了,看看做出來的效果

這里寫圖片描述

我們接著實現點擊item分享Apk文件:

 private class ItemClickListenerImpl implements AdapterView.OnItemClickListener{
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            File apkFile = mAppInfoList.get(position).getApkFile();
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_SEND);
            intent.setType("*/*");
            intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(apkFile));
            startActivity(intent);
        }
    }

在此處Apk文件放到intent中再調用系統自帶的分享功能即可。

界面做出來了,功能也實現了,再回過頭來看,其實不是很難。難點在于我們不知道——不知道它的icon和Apk文件到底放在哪里了。這讓我想起了拉姆斯菲爾德的一段話:

We also know there are known unknowns; that is to say we know there
are some things we do not know. But there are also unknown unknowns –
the ones we don’t know we don’t know.

嘿嘿,我們不是不會,只是不知道罷了。

源碼下載

來自: http://blog.csdn.net/lfdfhl/article/details/51286284

 本文由用戶 onau7184 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!