静态代码块里,如何拿到PackageManager?


近期遇到一个场景,
静态代码块里,无法拿到context,context.getPackageManager只在运行时适用,而静态代码块里无法做到,那么如何拿到PackageManager?

例如:

static {
       
        if(判断条件) {
            //执行静态方法;
        }
      
    }

 

从NfcAdapater里边找到了启发。

package android.nfc;

/**
 * Represents the local NFC adapter.
 * <p>
 * Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC
 * adapter for this Android device.
 *
 * <div class="special reference">
 * <h3>Developer Guides</h3>
 * <p>For more information about using NFC, read the
 * <a href="{@docRoot}guide/topics/nfc/index.html">Near Field Communication</a> developer guide.</p>
 * <p>To perform basic file sharing between devices, read
 * <a href="{@docRoot}training/beam-files/index.html">Sharing Files with NFC</a>.
 * </div>
 */
public final class NfcAdapter {
    static final String TAG = "NFC";

    /**
     * Helper to check if this device has FEATURE_NFC, but without using
     * a context.
     * Equivalent to
     * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)
     */
    private static boolean hasNfcFeature() {
        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm == null) {
            Log.e(TAG, "Cannot get package manager, assuming no NFC feature");
            return false;
        }
        try {
            return pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0);
        } catch (RemoteException e) {
            Log.e(TAG, "Package manager query failed, assuming no NFC feature", e);
            return false;
        }
    }
}

从代码里边,可以了解到,如果是想在静态代码块判断设备是否支持NFC feature, NfcAdapter和hasNfcFeature都是Public API,三方应用可以直接使用。

 

那么要判断Feature,还是要拿到PackageManager。

它这里并没有直接传递Context上下文到API,而知通过ActivityThread拿到IPackageManager。

package android.app;

/**
 * This manages the execution of the main thread in an
 * application process, scheduling and executing activities,
 * broadcasts, and other operations on it as the activity
 * manager requests.
 *
 * {@hide}
 */
public final class ActivityThread extends ClientTransactionHandler {
    /** @hide */
    public static final String TAG = "ActivityThread";
    private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565;
    static final boolean localLOGV = false;



    @UnsupportedAppUsage
    public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            return sPackageManager;
        }
        final IBinder b = ServiceManager.getService("package");
        sPackageManager = IPackageManager.Stub.asInterface(b);
        return sPackageManager;
    }

}

从框架ActivityThread API来看,它本身是个非公开API,其次它的getPackageManager()方法是在黑名单里边,三方应用无法使用。

 

那么我们自己能不能直接模仿以上函数体 通过IPackageManager来取得pm?

// IPackageManager.aidl
package android.content.pm;


/**
 *  See {@link PackageManager} for documentation on most of the APIs
 *  here.
 *
 *  {@hide}
 */
interface IPackageManager {
    void checkPackageStartable(String packageName, int userId);
    @UnsupportedAppUsage
    boolean isPackageAvailable(String packageName, int userId);

}

//ServiceManager.java
package android.os;



/** @hide */
public final class ServiceManager {
    private static final String TAG = "ServiceManager";
    private static final Object sLock = new Object();

    @UnsupportedAppUsage
    private static IServiceManager sServiceManager;

    /**
     * Returns a reference to a service with the given name.
     *
     * @param name the name of the service to get
     * @return a reference to the service, or <code>null</code> if the service doesn't exist
     */
    @UnsupportedAppUsage
    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return Binder.allowBlocking(rawGetService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

}

很遗憾,越是往里,越是限制多,IPackageManager和ServiceManager都是hide API,且ServiceManager.getService()也是黑名单,不宜给三方应用使用。

 

以上API仅仅适用于平台预置APP,例如:Settings。
在这里是满足我们需求的。
三方是无法只能通过SDK public API和上下文获取PackageManager。也就是说题记条件是不成立的,对普通应用开发这者来说,是要考虑设计是否合理了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值