运行在launcher中的apk ,且MainActivity为启动页
<activity
android:name="com.lyl.MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
为便于调试,修改了应用的包名,并且屏蔽了MainActivity的HOME属性。在debug时,会在windowManager.addView()处报错
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(AirMessageConfig.isCompleteFunction() ? R.layout.aty_air_main : R.layout.aty_air_main_low);
//加载状态栏
WindowManager windowManager = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_PHONE;
params.format = PixelFormat.RGBA_8888;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
params.gravity = Gravity.LEFT | Gravity.TOP;
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
mTitleView = LayoutInflater.from(this).inflate(R.layout.view_title_state, null);
windowManager.addView(mTitleView, params);
}
捕获异常
try {
windowManager.addView(mTitleView, params);
} catch (Exception e){
String msg = e.getMessage();
}
报错信息如下:
Unable to start activity ComponentInfo{xxx}: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@c721380 -- permission denied for this window type
百度后知道和targetSdkVersion有关系,在targetSdkVersion>=23的版本下编译,悬浮窗权限默认是关闭没有权限;在<23版本下编译悬浮窗权限是开启有权限的。通过代码搜索,发现targetSdkVersion为23,修改为22后测试OK。
使用系统签名后install到Android6.0的系统中,apk可正常运行【代码中argetSdkVersion为23】,推测已经申请了悬浮窗权限。通过settings可以看到,应用的悬浮窗权限已经开启,验证了推测的正确性。debug时,修改了包名,就和最初的应用时两个apk,该apk运行在Android6.0系统中就需要动态申请权限。此时就有两种方法解决该问题:动态申请权限 ,或修改targetSdkVersion为22。
若要申请权限:
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intent, 1);
}
}
Build.VERSION.SDK_INT是指当前设备的API等级,和targetSdkVersion一样。
PS:
targetSdkVersion时目标软件开发版本;
minSdkVersion是指安装Apk的最低版本号,手机系统低于这个版本号的是无法安装Apk;
compileSdkVersion属于Android编译项目时其中的一项配置,开发的应用程序在Android 7.0系统运行,不会以Android 7.0新增的行为运行,决定Android系统行为的仍然是targetSDKVersion,那么compileSDKVersion有什么用呢?选择最新的API版本,在编译的时候检查代码的错误和警告,提示开发者修改和优化,因为通常在Android项目中会引入第三方的支持库,支持库使用了23.1.1版本,compileSdkVersion的属性值至少为23.0.0,新版本的支持库的发布紧跟着对应的Android系统平台,能够更好的兼容。
同时,compileSDKVersion在不会被打包的APK文件中,targetSdkVersion和minSdkVersion将被打包到APK文件中,具体可以解压APK文件后,在AndroidManifest.xml文件可以看出。
参考:
Unable to add window android.view.ViewRootImpl -- permission denied for this window type