从此
📄文章 #️⃣专题 🌐酷站 👨‍💻技术 📺 📱

Android(AOSP)编程开发


综合/最新

Android开发Android UIAndroid API LevelsAndroid玩机

Android系统开放源码(墙外)
新:
  通过NsdManager/UPNP+TCP/UDP暴漏一个Android Service,自家App共享其已授权的能力。

死记、偏门:
  图标:Android 图标尺寸最低为 256x256 像素;Google Play商店网页展示图标最低要求为 32 位 PNG(含 alpha 透明层)、尺寸 512x512 像素、文件大小上限 1024 KB。
  可触摸 UI 元件的标准为 48dp=72px=9mm,即一个手指能够准确舒适触摸的最小尺寸,最小可点击区域。
  暂时禁用日志刷屏的应用:./adb shell pm disable-user com.google.android.apps.youtube.music
  约定:java包nonui下放BroadcastReceiver和Service,ui包则放Activity。
  授权通知才能Toast(前台Activity则永远能弹Toast) - NotificationService Error: Suppressing toast from package app.name by user request.
  全局异常处理:
    Application onCreate() - Thread.setDefaultUncaughtExceptionHandler(new UEH());

    public class UEH implements Thread.UncaughtExceptionHandler {
      Thread.UncaughtExceptionHandler defaultHandler;
      public UEH() { defaultHandler = Thread.getDefaultUncaughtExceptionHandler();}

      @Override public void uncaughtException(@NonNull Thread t, @NonNull Throwable e) {
        if (defaultHandler != null) { defaultHandler.uncaughtException(t, e); }
      } // 也可交回默认异常处理器
    }

  进程生命周期:
    ⬇前台进程(foreground process/oom_adj=0) - 有Activity界面直接交互的情况。
    ⬇可见进程(visible process) - 存在执行了Service.startForeground()的Service,则处于该状态;同时,还可通过startService()嵌套调startService()。
    ⬇服务进程(service process) - 如果有通过startService()启动的Service,则处于该状态,但在“无可见UI+无前台服务”数分钟后会强制降级为“缓存进程”,若在该Service里嵌套调startService()会报“Not allowed to start service Intent”,在降级前嵌套调startForegroundService()则不会报错;bindService()方式则不受影响;SYSTEM_ALERT_WINDOW+可见悬浮窗也可后台调startForegroundService()。
    ⬇缓存进程(cached process) - 降级为该状态后,系统会主动触发stopService();内存不足后会先拿其开刀,但若被其他app调起,则会提升至上方进程状态。
    无进程 - 即强制停止后的IMPORTANCE_GONE状态。

  查看PID: ./adb shell pidof com.openle.v1app.social.fullchannel
  查看优先级: ./adb shell cat /proc/[PID]/oom_adj

  前台服务(Foreground Services/FGS)任务管理器:下拉顶部通知栏,再二阶段下拉就能看到左下角的前台服务列表了,若用户在此点了“Stop”会连带整个应用关闭,但与“强制停止”不同的是,闹钟和WorkManager不会失效。
  [似乎已废弃]前台服务在24小时内连续运行20小时以上,会弹通知引起用户注意(“system-notification-long-running-fgs”),抑制1像素保活方案。
  系统源码添加白名单 - com.android.server.am.OomAdjuster、ProcessList.setOomAdj?

  开发者选项的“不保留活动”开启后,会导致进入二级页面时,按Home键就会销毁MainActivity了,二级页面再finish()就找不到MainActivity了,故时间充裕的话,应测测看:
    判断后提示用户关掉:Settings.Global.getInt(getContentResolver(), Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0);

Android虚拟机:
  Android Runtime(ART)虚拟机取代了早期的Dalvik虚拟机,但均使用由d8转换后的DEX字节码格式(*.dex或*.aar),无法识别纯Java编译打包的*.class或*.jar文件。
  Java转Dex命令:d8 MyProject/app/build/intermediates/classes/debug/*/*.class 或 d8 java.jar --output out.dex
  动态载入及反射调用:DexClassLoader对象。

内容

Android BroadcastReceiver:
  开机广播:
    说明 - [targetSdk = 34 亲测]能启动部分前台服务,但只有授权通知后,才允许Toast和显示“前台服务运行通知”;[未测]起个悬浮窗是否能Toast?
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <receiver android:name=".nonui.BootReceiver" android:enabled="true" android:exported="true">
      <intent-filter><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter>
    </receiver>

Android Service:
  前台服务:
    说明 - Activity启动的前台服务会弹出“前台服务运行通知”,但BOOT_COMPLETED则必须再授予通知权限后才会通知,不授权则只是不通知,而不会影响该服务运行。
    短期服务(android:foregroundServiceType="shortService") - 3分钟后系统会触发onTimeout(int startId)来stopSelf(),优势是支持在 BOOT_COMPLETED 内启动,且不需要上架Google Play的人工审核。

调起Android系统内置邮箱应用: startActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_EMAIL).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

Android网络广播默认禁用,需要WifiManager.createMulticastLock(String tag)来启用。

存储:
  通过 Environment.DIRECTORY_PICTURES 可获取用户更改的默认图片存储位置,实际路径通常是: /storage/emulated/0/Pictures/;但应首选非写死的 ContentUri。
  contentValues.put(MediaStore.Images.ImageColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES); // 指定约定目录或子目录;或 put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/subDir")


保活:
  Android一像素Activity进程保活
  15分钟区间保活:WorkManager+闹钟

  ROOT保活:
    ./adb root
    ./adb remount
    ./adb push system/priv-app/folder_name/ apk_path
    ./adb shell sync
    ./adb reboot

  进程活跃度受限:
    var usm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
    var asb = usm.getAppStandbyBucket(); // ./adb shell am get-standby-bucket PACKAGE_NAME
    if (asb > UsageStatsManager.STANDBY_BUCKET_ACTIVE) {
        //应用可能受限
        System.out.println(asb);
    }


FGS 任务管理器 向上滑动 强行停止
立即从内存中移除应用
停止媒体播放
停止 FGS/移除关联的通知
移除 activity 返回堆栈
从历史记录中移除应用
取消预定作业
取消闹钟

其他

mDNS:
  根据树莓派服务类型检索网络地址:nsdManager.discoverServices("_workstation._tcp.",...);
    触发onServiceFound入参判断nsdServiceInfo.getServiceName().startsWith("raspberrypi")

  树莓派注册的服务类型:nsdServiceInfo.setServiceType("_workstation._tcp.");