Android11.0系统中实现静默安装并启动App以及静默卸载

这篇具有很好参考价值的文章主要介绍了Android11.0系统中实现静默安装并启动App以及静默卸载。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

静默安装并启动App以及静默卸载

本文描述Android11中通过修改系统PackageInstaller应用支持静默安装App,并启动安装的App。

修改PackageInstaller

PackageInstaller是系统中专门负责app安装的App,静默安装逻辑添加到此应用中,应用所在路径 /frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/

  1. 添加SilenceInstallManager,路径为 /frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/SilenceInstallManager.java;

package com.android.packageinstaller;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.ResolveInfo;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.ArrayMap;
import android.util.Log;

import androidx.annotation.NonNull;

import com.android.internal.content.PackageHelper;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import android.content.pm.IPackageDeleteObserver;


final class SilenceInstallManager {
    private static final String TAG = "SilenceInstallManager";

    private static final int MSG_WHAT_INSTALL_FINISH_SUCCESS = 0;
    private static final int MSG_WHAT_INSTALL_FINISH_FAIL = 1;
    private static final int MSG_WHAT_UNINSTALL_COMPLETE = 2;

    private Context mContext;

    @SuppressLint("NewApi")
    private ArrayMap<Integer, InstallAppInfo> InstallAppInfoMap = new ArrayMap<>();


    private static volatile SilenceInstallManager INSTANCE;

    private SilenceInstallManager(Context context) {
        mContext = context;
    }

    public static SilenceInstallManager getInstance(Context context) {
        if (null == INSTANCE) {
            synchronized (SilenceInstallManager.class) {
                if (null == INSTANCE) {
                    INSTANCE = new SilenceInstallManager(context.getApplicationContext());
                }
            }
        }
        return INSTANCE;
    }


    @SuppressLint("NewApi")
    private PackageInstaller.SessionCallback mSessionCallback = new PackageInstaller.SessionCallback() {
        @Override
        public void onCreated(int sessionId) {
            Log.d(TAG, "onCreated---->" + sessionId);
        }

        @Override
        public void onBadgingChanged(int sessionId) {
//            Log.w(TAG, "SilenceInstallReceiver onBadgingChanged---->" + sessionId);
        }

        @Override
        public void onActiveChanged(int sessionId, boolean active) {
//            Log.w(TAG, "SilenceInstallReceiver onActiveChanged---->" + sessionId + "  active--->" + active);
        }

        @Override
        public void onProgressChanged(int sessionId, float progress) {
//            Log.w(TAG, "SilenceInstallReceiver onProgressChanged---->" + sessionId + "  progress--->" + progress);
        }

        @Override
        public void onFinished(int sessionId, boolean success) {
            Log.d(TAG, "onFinished---->" + sessionId + "  success--->" + success);
            Message msg = Message.obtain();
            msg.what = MSG_WHAT_INSTALL_FINISH_SUCCESS;
            msg.arg1 = sessionId;
            msg.obj = success;
            mHandler.sendMessage(msg);
        }
    };

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @Override
        public void dispatchMessage(@NonNull Message msg) {
            mContext.getPackageManager().getPackageInstaller().unregisterSessionCallback(mSessionCallback);
            if (msg.what == MSG_WHAT_INSTALL_FINISH_SUCCESS) {
                boolean result = (boolean) msg.obj;
                int sessionId = msg.arg1;
                InstallAppInfo info = InstallAppInfoMap.remove(sessionId);
                if (result) {
                    Log.d(TAG, "install success");
                    if (null != info) {
                        if (info.isLaunch && null != info.info && null != info.info.packageName && !"".equals(info.info.packageName)) {
                            launchApp(info.info.packageName);
                        }

                        File f = new File(info.filePath);
                        if (f.exists()) {
                            f.delete();
                        }
                    }
                } else {
                    Log.d(TAG, "install fail");
                }
            } else if (msg.what == MSG_WHAT_INSTALL_FINISH_FAIL) {
                int sessionId = msg.arg1;
                if (sessionId != -1) {
                    InstallAppInfoMap.remove(sessionId);
                }
                Log.d(TAG, "install fail");
            } else if (msg.what == MSG_WHAT_UNINSTALL_COMPLETE) {
                Log.d(TAG, "uninstall complete--->" + msg.arg1);
                if (msg.arg1 == PackageManager.DELETE_SUCCEEDED) {
                    Log.d(TAG, "delete succeeded");
                } else {
                    Log.d(TAG, "delete fail");
                }
            }
        }
    };

    public void silenceInstall(String appFilePath, boolean launch) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            mContext.getPackageManager().getPackageInstaller().registerSessionCallback(mSessionCallback);

            PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
            params.setInstallAsInstantApp(false);
            params.setInstallReason(PackageManager.INSTALL_REASON_USER);

            File file = new File(appFilePath);
            if (!file.exists()) {
                sendFailMsg(-1);
                return;
            }

            try {
                PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
                params.setAppPackageName(pkg.packageName);
                params.setInstallLocation(pkg.installLocation);
                params.setSize(
                        PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
            } catch (PackageParser.PackageParserException e) {
                Log.e(TAG, "Cannot parse package " + file + ". Assuming defaults.");
                Log.e(TAG,
                        "Cannot calculate installed size " + file + ". Try only apk size.");
                params.setSize(file.length());
            } catch (IOException e) {
                Log.e(TAG,
                        "Cannot calculate installed size " + file + ". Try only apk size.");
                params.setSize(file.length());
            }

            try {
                PackageInfo mPkgInfo = PackageUtil.getPackageInfo(mContext, file, PackageManager.GET_PERMISSIONS);
                int mSessionId = mContext.getPackageManager().getPackageInstaller().createSession(params);
                InstallAppInfo installAppInfo = new InstallAppInfo(mSessionId, appFilePath, mPkgInfo, launch);
                InstallAppInfoMap.put(mSessionId, installAppInfo);

                InstallingAsyncTask mInstallingTask = new InstallingAsyncTask(mContext, appFilePath, mSessionId);
                mInstallingTask.execute();
            } catch (IOException e) {
                e.printStackTrace();
                sendFailMsg(-1);
            }
        }
    }

    private void sendFailMsg(int sessionId) {
        Message msg = Message.obtain();
        msg.what = MSG_WHAT_INSTALL_FINISH_FAIL;
        msg.arg1 = sessionId;
        mHandler.sendMessage(msg);
    }


    @SuppressLint("NewApi")
    private final class InstallingAsyncTask extends AsyncTask<Void, Void,
            PackageInstaller.Session> {

        private Context mContext;
        private String mAppPath;
        private int mSessionId;

        public InstallingAsyncTask(Context context, String appPath, int sessionId) {
            mContext = context;
            mAppPath = appPath;
            mSessionId = sessionId;
        }

        @Override
        protected PackageInstaller.Session doInBackground(Void... params) {
            PackageInstaller.Session session;
            try {
                session = mContext.getPackageManager().getPackageInstaller().openSession(mSessionId);
            } catch (IOException e) {
                return null;
            }

            session.setStagingProgress(0);

            try {
                File file = new File(mAppPath);

                try (InputStream in = new FileInputStream(file)) {
                    long sizeBytes = file.length();
                    try (OutputStream out = session
                            .openWrite("PackageInstaller", 0, sizeBytes)) {
                        byte[] buffer = new byte[1024 * 1024];
                        while (true) {
                            int numRead = in.read(buffer);

                            if (numRead == -1) {
                                session.fsync(out);
                                break;
                            }

                            if (isCancelled()) {
                                session.close();
                                break;
                            }

                            out.write(buffer, 0, numRead);
                            if (sizeBytes > 0) {
                                float fraction = ((float) numRead / (float) sizeBytes);
                                session.addProgress(fraction);
                            }
                        }
                    }
                }

                return session;
            } catch (IOException | SecurityException e) {
                Log.e(TAG, "Could not write package", e);
                session.close();
                return null;
            }
        }

        @Override
        protected void onPostExecute(PackageInstaller.Session session) {
            if (session != null) {
                Intent broadcastIntent = new Intent();
                PendingIntent pendingIntent = PendingIntent.getBroadcast(
                        mContext,
                        1,
                        broadcastIntent,
                        PendingIntent.FLAG_UPDATE_CURRENT);

                session.commit(pendingIntent.getIntentSender());

                session.close();

                Log.d(TAG, "send install PendingIntent----->");
            } else {
                mContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
                sendFailMsg(mSessionId);

                File f = new File(mAppPath);
                if (f.exists()) {
                    f.delete();
                }

                Log.e(TAG, "copy fail delete file----->");
            }

            mContext = null;
            mAppPath = "";
            mSessionId = -1;
        }
    }


    private class InstallAppInfo {
        private int sessionId;
        private String filePath;
        private PackageInfo info;
        private boolean isLaunch;

        public InstallAppInfo(int sessionId, String filePath, PackageInfo info, boolean isLaunch) {
            this.sessionId = sessionId;
            this.filePath = filePath;
            this.info = info;
            this.isLaunch = isLaunch;
        }

        public int getSessionId() {
            return sessionId;
        }

        public String getFilePath() {
            return filePath;
        }

        public PackageInfo getInfo() {
            return info;
        }

        public boolean isLaunch() {
            return isLaunch;
        }
    }


    private void launchApp(String appPackageName) {
        Intent mLaunchIntent = mContext.getPackageManager().getLaunchIntentForPackage(appPackageName);
        if (mLaunchIntent != null) {
            List<ResolveInfo> list = mContext.getPackageManager().queryIntentActivities(mLaunchIntent, 0);
            if (list != null && list.size() > 0) {
                Log.d(TAG, "launch app--->");
                mContext.startActivity(mLaunchIntent);
            }
        }
    }


    public void silenceUninstall(String packageName) {
        Log.i(TAG, "silenceUninstall--->" + packageName);
        PackageDeleteObserver observer = new PackageDeleteObserver();
        mContext.getPackageManager().deletePackage(packageName, observer, PackageManager.DELETE_ALL_USERS);
    }

    private class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
        public void packageDeleted(String packageName, int returnCode) {
            Message msg = mHandler.obtainMessage(MSG_WHAT_UNINSTALL_COMPLETE);
            msg.arg1 = returnCode;
            msg.obj = packageName;
            mHandler.sendMessage(msg);
        }
    }
}

  1. 添加SilenceInstallReceiver,路径为 /frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/SilenceInstallReceiver.java;

package com.android.packageinstaller;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;


public class SilenceInstallReceiver extends BroadcastReceiver {
    public static final String SILENCE_INSTALL_APP = "com.android.packageinstaller.ACTION_SILENCE_INSTALL";
    public static final String SILENCE_INSTALL_KEY = "silence_install";
    public static final String IS_LAUNCH_KEY = "is_launch";
    public static final String APP_URI_KEY = "app_uri";


    @Override
    public void onReceive(Context context, Intent intent) {
        if (SILENCE_INSTALL_APP.equals(intent.getAction())) {
            Uri uri = intent.getParcelableExtra(APP_URI_KEY);
            boolean isLaunch = intent.getBooleanExtra(IS_LAUNCH_KEY, false);
            SilenceInstallManager.getInstance(context).silenceInstall(uri.getPath(), isLaunch);
        }

    }

}

  1. InstallStart是PackageInstaller程序安装app的入口activity,修改InstallStart,添加静默安装逻辑分支,路径为 /frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java;
//********省略代码******

  protected void onCreate(@Nullable Bundle savedInstanceState) {

        //********省略代码******
        if (isSessionInstall) {
            nextActivity.setClass(this, PackageInstallerActivity.class);
        } else {
            Uri packageUri = intent.getData();

            if (packageUri != null && packageUri.getScheme().equals(
                    ContentResolver.SCHEME_CONTENT)) {
                // [IMPORTANT] This path is deprecated, but should still work. Only necessary
                // features should be added.

                // Copy file to prevent it from being changed underneath this process
                nextActivity.setClass(this, InstallStaging.class);
            } else if (packageUri != null && packageUri.getScheme().equals(
                    PackageInstallerActivity.SCHEME_PACKAGE)) {
                nextActivity.setClass(this, PackageInstallerActivity.class);
            } else {
                Intent result = new Intent();
                result.putExtra(Intent.EXTRA_INSTALL_RESULT,
                        PackageManager.INSTALL_FAILED_INVALID_URI);
                setResult(RESULT_FIRST_USER, result);

                nextActivity = null;
            }
        }

       //安装请求中如果带静默安装标识,执行静默安装操作
        if (intent.getBooleanExtra(SilenceInstallReceiver.SILENCE_INSTALL_KEY, false)) {
            StagingAsyncAppTask mStagingTask = new StagingAsyncAppTask(intent.getBooleanExtra(SilenceInstallReceiver.IS_LAUNCH_KEY, false));
            mStagingTask.execute(getIntent().getData());
            return;
        }

        if (nextActivity != null) {
            startActivity(nextActivity);
        }
        finish();
}


    @SuppressLint("NewApi")
    private final class StagingAsyncAppTask extends AsyncTask<Uri, Void, File> {

        private boolean mIsLaunch;

        public StagingAsyncAppTask(boolean isLaunch){
            mIsLaunch = isLaunch;
        }


        @Override
        protected File doInBackground(Uri... params) {
            Log.d(LOG_TAG, "copy file from user app start");
            if (params == null || params.length <= 0) {
                return null;
            }
            Uri packageUri = params[0];
            try (InputStream in = getContentResolver().openInputStream(packageUri)) {
                // Despite the comments in ContentResolver#openInputStream the returned stream can
                // be null.
                if (in == null) {
                    return null;
                }

                File mStagedFile = TemporaryFileManager.getStagedFile(InstallStart.this);

                try (OutputStream out = new FileOutputStream(mStagedFile)) {
                    byte[] buffer = new byte[1024 * 1024];
                    int bytesRead;
                    while ((bytesRead = in.read(buffer)) >= 0) {
                        // Be nice and respond to a cancellation
                        out.write(buffer, 0, bytesRead);
                    }
                }
                return mStagedFile;
            } catch (IOException | SecurityException | IllegalStateException e) {
                Log.w(LOG_TAG, "Error staging apk from content URI", e);
            }
            return null;
        }

        @Override
        protected void onPostExecute(File installFile) {
            if (null != installFile) {
                // Now start the installation again from a file
                Log.d(LOG_TAG, "copy file from user app finish");

                Intent installIntent = new Intent(SilenceInstallReceiver.SILENCE_INSTALL_APP);
                installIntent.putExtra(SilenceInstallReceiver.APP_URI_KEY, Uri.fromFile(installFile));
                installIntent.putExtra(SilenceInstallReceiver.IS_LAUNCH_KEY, mIsLaunch);
                installIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                installIntent.setPackage("com.android.packageinstaller");
                sendBroadcast(installIntent);

                Log.d(LOG_TAG, "send to install");
            } else {
                Log.d(LOG_TAG, "copy file from user app fail");
            }

            finish();
        }
    }

//********省略代码******
  1. UninstallerActivity是PackageInstaller程序卸载app的入口activity,修改UninstallerActivity,添加静默卸载逻辑分支,路径为 /frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java;

//********省略代码******
public void onCreate(Bundle icicle){
         //********省略代码******
        
        //添加静默卸载逻辑
        if (intent.getBooleanExtra(SilenceInstallReceiver.SILENCE_INSTALL_KEY, false)) {
            SilenceInstallManager.getInstance(this).silenceUninstall(mPackageName);
            return;
        }

        showConfirmationDialog();
}

//********省略代码******
  1. 修改PackageInstallerApplication,路径为 /frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerApplication.java;
//********省略代码******

public class PackageInstallerApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        PackageItemInfo.forceSafeLabels();

		//添加管理类初始化
        SilenceInstallManager.getInstance(this);
    }
}

//********省略代码******
  1. 修改AndroidManifest.xml,路径为 /frameworks/base/packages/PackageInstaller/AndroidManifest.xml;
//********省略代码******

//添加后台启动activity权限
<uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />

//********省略代码******

<receiver android:name=".SilenceInstallReceiver"
            android:exported="false">
            <intent-filter android:priority="1">
                <action android:name="com.android.packageinstaller.ACTION_SILENCE_INSTALL" />
            </intent-filter>
        </receiver>

//********省略代码******
  1. Android10开始,系统限制在没有用户交互的情况下在后台启动Activity,会输出如下信息

Background activity start [callingPackage: com.android.packageinstaller; callingUid: 10069; isCallingUidForeground: false; callingUidHasAnyVisibleWindow: false; callingUidProcState: CACHED_EMPTY; isCallingUidPersistentSystemProcess: false; realCallingUid: 10069; isRealCallingUidForeground: false; realCallingUidHasAnyVisibleWindow: false; realCallingUidProcState: CACHED_EMPTY; isRealCallingUidPersistentSystemProcess: false; originatingPendingIntent: null; isBgStartWhitelisted: false; intent: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 pkg=com.qiyi.video cmp=com.qiyi.video/.WelcomeActivity }; callerApp: ProcessRecord{ba2b2ca 2471:com.android.packageinstaller/u0a69}]

Abort background activity starts from 10069

当开发的App切换到后台后,就无法进行应用安装请求,ActivityStarter.java中的shouldAbortBackgroundActivityStart()方法在判断是否能够启动activity,在这里添加修改逻辑处理,路径为 /frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java;文章来源地址https://www.toymoban.com/news/detail-773259.html

//********省略代码******

boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
            final String callingPackage, int realCallingUid, int realCallingPid,
            WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
            boolean allowBackgroundActivityStart, Intent intent) {

//********省略代码******

        // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
        if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
            Slog.w(TAG, "Background activity start for " + callingPackage
                    + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
            return false;
        }
        
        //添加判断逻辑,通过allowed_Background标识决定是能够启动
        if (intent.getBooleanExtra("allowed_Background", false)) {
            Slog.w(TAG, "allowed_Background.");
            return false;
        }
    
       //********省略代码******
}

//********省略代码******

第三方App请求静默安装及卸载

  1. 在开发的app中使用下面方法请求安装

    private void installTest() {
        String appPath = getExternalFilesDir(null).getAbsolutePath() + File.separator + "aiqiyi.apk";

        File appFile = new File(appPath);
        if (!appFile.exists()) {
            showToast("请在" + getExternalFilesDir(null).getAbsolutePath() + File.separator + "目录中放置升级文件");
            return;
        }

        Uri uri = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".file_provider", appFile);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Intent installApkIntent = new Intent();
            installApkIntent.setAction(Intent.ACTION_VIEW);
            installApkIntent.addCategory(Intent.CATEGORY_DEFAULT);
            installApkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            installApkIntent.setDataAndType(uri, "application/vnd.android.package-archive");
            installApkIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            //设置静默安装标识
            installApkIntent.putExtra("silence_install", true);
            //设置安装完成是否启动标识
            installApkIntent.putExtra("is_launch", true);
            //设置后台中启动activity标识
            installApkIntent.putExtra("allowed_Background", true);
            if (getPackageManager().queryIntentActivities(installApkIntent, 0).size() > 0) {
                startActivity(installApkIntent);
            }
        }
    }

  1. 在开发的app中使用下面方法请求卸载
    public boolean requestSilenceUninstall(Context context, String packageName) {
        if (null == packageName || "".equals(packageName)) {
            return false;
        }

        try {
            PackageInfo packinfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
            String[] list = packinfo.requestedPermissions;
            boolean hasPermission = false;
            if (null != list) {
                for (int i = 0; i < list.length; i++) {
                    if (Manifest.permission.QUERY_ALL_PACKAGES.equals(list[i])) {
                        hasPermission = true;
                        break;
                    }
                }
            }
            if (!hasPermission) {
                throw new RuntimeException("need permission " + Manifest.permission.QUERY_ALL_PACKAGES);
            }
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(e);
        }

        if (!checkExistForApp(context, packageName)) {
            return false;
        }

        Intent intent = new Intent(Intent.ACTION_DELETE);
        intent.setData(Uri.parse("package:" + packageName));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra("allowed_Background", true);
        intent.putExtra("silence_install", true);
        context.startActivity(intent);

        return true;
    }

到了这里,关于Android11.0系统中实现静默安装并启动App以及静默卸载的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android11.0 生成系统签名.jks文件并对Apk进行签名

    V2签名 对应用手动进行系统签名,需要platform.pk8,platform.x509.pem,signapk.jar这三个文件,应用的AndroidManifest.xml中需要添加 android:sharedUserId=“android.uid.system” ,然后输入以下命令就可得到签名后的apk文件: 如果你的应用 targetSdkVersion=30 ,在7.0以上的设备上安装不成功,会报以

    2024年02月07日
    浏览(56)
  • Android 11.0 动态修改SystemProperties中ro开头系统属性的值

    需求: 在11.0的产品开发中,对于定制功能的需求很多,有些机型要求可以修改系统属性值,对于系统本身在10.0以后为了系统安全性,不允许修改ro开头的SystemProperties的值,所以如果要求修改ro的相关系统属性,就得看在设置SystemProperties的相关值的要求,修改这部分要求就可

    2024年02月05日
    浏览(90)
  • Android 11.0 系统修改usb连接电脑mtp和PTP的显示名称

      在11.0的系统产品rom定制化开发中,在usb模块otg连接电脑,调整为mtp文件传输模式的时候,这时可以在电脑看到手机的内部存储 显示在电脑的盘符中,会有一个mtp名称做盘符,所以为了统一这个名称,就需要修改这个名称,接下来分析下处理的方法来解决这个问题 MTP的全称

    2024年01月17日
    浏览(52)
  • Android 11.0 系统限制上网系统之iptables用IOemNetd实现创建子链功能的实现

    在11.0的系统rom定制化开发中,对于限制系统上网功能中,需要在system中netd网络这块的产品开发中,会要求设置屏蔽ip地址之内的功能, liunx中iptables命令也是比较重要的,接下来就来在IOemNetd这块实现创建子链的相关功能 在android原生系统中,iptables是在网络过滤包模块非常重

    2024年02月13日
    浏览(96)
  • Android 11.0 系统限制上网系统之iptables用IOemNetd实现删除子链功能的实现

    在11.0的系统rom定制化开发中,对于限制系统上网功能中,在system中netd网络这块的产品开发中,会要求设置屏蔽ip地址之内的功能, liunx中iptables命令也是比较重要的,接下来就来在IOemNetd这块实现删除创建子链的相关功能 在android原生系统中,iptables是在网络过滤包模块非常重

    2024年02月16日
    浏览(50)
  • 【干货】Android系统定制基础篇:第三部分(Android静默安装、Android支持usb打印机)

    一些产品要求APP在升级时能够实现静默安装,而无需弹出安装界面让用户确认。这里提出两种实现方案: 方案一 APP调用『pm』命令实现静默安装,此方案无须修改Android源码,但需要root权限。 方案二 修改Android PackageInstaller 源码,增加Intent参数来指定是否要静默安装,同时支

    2024年02月10日
    浏览(47)
  • Android11.0 launcher修改为单层

    OS: RK3568 Android11.0 现在的产品基本都是按照手机样式去做,所以需要把系统默认的Launcher样式,去掉抽屉改为单层显示,也就是把所有的app添加到workspace中。 以下修改是在设备横屏模式下进行 。 1.添加一个宏开关控制Launcher单双层显示 源码: /packages/apps/Launcher3/src/com/android/

    2024年02月08日
    浏览(58)
  • Android11.0 导航栏添加图标截屏

    需求: 导航栏添加截屏和电源键图标,控制截屏和用于设备重启关机功能。设置中添加延时截屏和控制截屏图标显示开关。 1. 导航栏添加图标 1.1 添加布局文件和图标icon 在layout目录下添加nav_power.xml和screenshot.xml文件 frameworks/base/packages/SystemUI/res/layout/nav_power.xml frameworks/base

    2024年02月15日
    浏览(55)
  • Android 11.0 SystemUI下拉状态栏禁止QuickQSPanel展开

       在11.0系统rom产品定制化开发中,对于SystemUI定制开发功能也有不少的,增加快捷功能模块,隐藏状态栏图标项目开发需要要求定制QSPanel相关UI和开发功能, 要求首次下拉后展示快捷功能模块以后就是显示QuickQSPanel而不展开QSPanel,接下来要从下滑手势下拉出状态栏分析功能

    2024年02月08日
    浏览(69)
  • Android 11.0 以太网设置默认静态ip地址

    在11.0的系统rom开发过程中,在进行以太网产品开发的过程中,有功能要求设置默认静态ip地址的功能,不使用动态ip, 方便ip地址管理所以就需要熟悉以太网的ip设置流程,然后设置对应的ip地址就可以了

    2024年02月16日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包