【Android】-- 如何对APP版本控制/更新?

news2024/9/20 16:50:40

目录

一、 前提准备

1、获取服务器

2、使用工具操作云服务器

 二、Json格式网页

 三、创建file_paths.xml及修改AndroidManifest.xml

四、在java代码加入更新检测代码


效果如图:

        可以强制更新和非强制更新,和浏览器下载安装包。

一、 前提准备

1、获取服务器

        首先去获取云服务器,如:阿里云服务器(学生可免费领取六个月)、腾讯云服务器、华为云服务器等。具体操作参考:从零开始用阿里云服务器搭建网页_阿里云怎么装修网页打开_zstar-_的博客-CSDN博客

        云服务器用于存放json格式网页和安装包,json可以对app进行版本控制更新、显示版本、显示更新内容、提供安装包下载位置等信息。

2、使用工具操作云服务器

        可以使用指令控制,也可以使用工具控制服务器,选用putty软件进行远程控制,winSCP软件进行文件传输。下载链接

       以下是winSCP界面的服务器文件:可按下面文件找到存放安装包和网页的文件夹。

如下就是对APP进行版本更新的网页和安装包存放的文件夹:

 二、Json格式网页

以下是html网页代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>UFCFans</title>
</head>
<body>
<pre><code id="json"></code></pre>
</body>
<script type="text/javascript">
let btn = document.querySelector('#json');
let data = {"hasUpdate": true,"NoIgnorable": true,
"versionCode": 2,
"versionName": "2.0",
"updateLog": "\n1、新增本地缓存。\n2、解决部分BUG。\n3、优化使用体验。",
"apkUrl": "http://8.130.127.118:8080/ufcfans.apk",
"webUrl": "http://8.130.127.118:8080/ufcfans.apk",
"apkSize": "29.5MB"};
btn.textContent = JSON.stringify(data, null, 2);
</script>
</html>

下面是相关变量说明:

{
    hasUpdate: true,  //是否有更新 默认true
    NoIgnorable: true, //不 可忽略更新  强制:true 非强制:false
    versionCode: 51,   //服务端的版本号  
    versionName: "2.4.1", //服务端的版本名
    updateLog: "\n1、更改保存图片的存储路径。\n2、更改软件更新的提示模式。\n3、调整非强制更新控制方式。\n4、新增存储权限的申请授权位置。", //更新提示内容
    apkUrl: "https://www.yuming.com/assets/a某o130.apk",//新版本APK直链下载地址
    webUrl: "https://yirj.gitee.io/update111",//浏览器更新链接,随意放(直链、蓝奏、官网均可)
    apkSize: "29.5MB" //新版本的大小 随意写就好
}

 三、创建file_paths.xml及修改AndroidManifest.xml

 创建file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

 修改AndroidManifest.xml

 

    <!-- 拥有完全的网络访问权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 修改或删除您的USB存储设备中的内容 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- 查看网络连接 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
        .....
        android:label="@string/app_name"
        android:requestLegacyExternalStorage="true">

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
        .........
</application>

四、在java代码加入更新检测代码

        在软件的检测更新界面的Oncreate方法下,加入检测更新的代码。

        NoIgnorable变量为true则强制更新,无取消按钮,为false有取消按钮;

versionName, updateLog, apkSize, apkUrl, webUrl和upl变量为你的网页网址,如:UFCFansicon-default.png?t=N5F7http://8.130.127.118:8080

public static JSONObject jSONObject = null;
    private static boolean hasUpdate = true;
    private static boolean NoIgnorable; //是否有更新。 不可忽略的更新
    private static int versionCode = 0;
    private static String versionName, updateLog, apkSize, apkUrl, webUrl;
    private static  String[] upl;
   /**
     * 获取当前使用的软件包的版本号
     */
    public int getVersionCode() {
        try {
            //获取packagemanager的实例
            PackageManager packageManager = getPackageManager();
            //getPackageName()是你当前类的包名,0代表是获取版本信息
            PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0);
            Log.e("TAG", "版本号" + packInfo.versionCode);  //更新软件用的是版本号
            return packInfo.versionCode;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 1;
    }

    /**
     * 提示版本更新的对话框
     */
    public void showDialogUpdate() {
        //hasUpdate为true且程序版本号<服务端版本号,提示用户更新
        if (NoIgnorable) { //NoIgnorable为true 就是强制更新,无“取消”按钮
            // 这里的属性可以一直设置,因为每次设置后返回的是一个builder对象
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setCancelable(false); //开启强制更新,无法触摸外部关闭
            builder.setTitle("是否升级到" + versionName + "版本?").
                    // 设置提示框的图标
//                            setIcon(R.drawable.ic_launcher).
                    // 设置要显示的信息
                            setMessage("新版本大小:" + apkSize + "\n" + updateLog).
                    // 设置确定按钮
                            setPositiveButton("更新", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            loadNewVersionProgress();//程序内直接下载最新的版本程序
                        }
                    }).
                    setNeutralButton("浏览器下载", new DialogInterface.OnClickListener() {//中性按钮 应用内下载失败可用它更新
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Uri uri = Uri.parse(webUrl);
                    Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                    startActivity(intent);
                    finish(); //强制更新,点击后销毁应用
                }
            });
            // 显示对话框
            builder.create().show();
        } else {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
//            builder.setCancelable(false); //非强制更新,屏蔽此行,触摸外部或退出键可关闭
            builder.setTitle("是否升级到" + versionName + "版本?").
                    setMessage("新版本大小:" + apkSize + "\n" + updateLog).
                    setPositiveButton("更新", new DialogInterface.OnClickListener() {//正按钮
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            loadNewVersionProgress();//下载最新的版本程序
                        }
                    }).setNegativeButton("取消", new DialogInterface.OnClickListener() {//负按钮
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
//                        finish(); //屏蔽销毁,不做任何处理
                        }
                    }).setNeutralButton("浏览器下载", new DialogInterface.OnClickListener() {//中性按钮
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Uri uri = Uri.parse(webUrl);
                            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                            startActivity(intent);
                            //finish(); //屏蔽销毁,访问浏览器,程序不会退出
                        }
                    });
            // 显示对话框
            builder.create().show();
        }
    }

    //轮询验证两个更新链接,返回有效链接
    public static String checkUrl(String[] ltl) {
        String resultUrl = null;
        for (String url : ltl) {
            resultUrl = url;
            try {
                //调用检查链接是否有效的方法
                String result = get(url);
                if (result != null && result.length() != 0) {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultUrl;
    }

    //检查更新链接是否有效的方法
    public static String get(String url) {
        URL infoUrl = null;
        InputStream inStream = null;
        String line = "";
        try {
            infoUrl = new URL(url);
            URLConnection connection = infoUrl.openConnection();
            HttpURLConnection httpConnection = (HttpURLConnection) connection;
            int responseCode = httpConnection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                inStream = httpConnection.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "utf-8"));
                StringBuilder strber = new StringBuilder();
                while ((line = reader.readLine()) != null)
                    strber.append(line + "\n");
                inStream.close();
                int start = strber.indexOf("{");
                int end = strber.indexOf("}");
                String json = strber.substring(start, end + 1);
                return json;
            }
        } catch (MalformedURLException e) {
        } catch (IOException e) {
        }
        return "";
    }

    /**
     * 使用检查过的有效链接,获取服务端json数据
     */
    public static JSONObject GetServerJson() {
        URL infoUrl = null;
        InputStream inStream = null;
        String line = "";
        try {
            String uurl = checkUrl(upl);
            infoUrl = new URL(uurl); //json格式信息的API,使用案例。
            URLConnection connection = infoUrl.openConnection();
            HttpURLConnection httpConnection = (HttpURLConnection) connection;
            int responseCode = httpConnection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                inStream = httpConnection.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "utf-8"));
                StringBuilder strber = new StringBuilder();
                while ((line = reader.readLine()) != null)
                    strber.append(line + "\n");
                inStream.close();
                int start = strber.indexOf("{");
                int end = strber.indexOf("}");
                String json = strber.substring(start, end + 1);
                if (json != null) {
                    try {
                        jSONObject = new JSONObject(json);
                        hasUpdate = jSONObject.getBoolean("hasUpdate");
                        NoIgnorable = jSONObject.getBoolean("NoIgnorable");
                        versionCode = jSONObject.getInt("versionCode");
                        versionName = jSONObject.getString("versionName");
                        updateLog = jSONObject.getString("updateLog");
                        apkSize = jSONObject.getString("apkSize");
                        apkUrl = jSONObject.getString("apkUrl");
                        webUrl = jSONObject.getString("webUrl");
                        return jSONObject;
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 应用内直链升级方法,下载新版本程序
     */
    private void loadNewVersionProgress() {
        ProgressDialog pd = new ProgressDialog(this);
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        //获取手机的根目录存储位置,以及直链链接最后一个“/”后文字作为文件名展示在界面
        pd.setMessage("下载最新版本安装包到:" + Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + apkUrl.substring(apkUrl.lastIndexOf("/") + 1));
        pd.setCancelable(false); //开启强制更新,触摸屏幕其他位置无法关闭
        pd.show();

        //启动子线程下载任务
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                try {
                    File file = getFileFromServer(apkUrl, pd);  //调用下载服务方法动态显示进度
                    //sleep(2000);//设置休眠两秒之后再启动安装
                    installApk(file);  //下载完成直接安装
//                    pd.dismiss(); //屏蔽,结束掉进度条对话框,防止强制更新出Bug
                } catch (Exception e) {
                    //直链下载apk异常失败提示容错。
                    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                    builder.setCancelable(false);//开启强制更新,触摸屏幕其他位置无法关闭
                    builder.setTitle("下载失败:").setMessage("1.请检查存储权限是否开启。\n2.请检查网络连接是否正常。\n3.使用浏览器下载新版本。\nother:"+e.getMessage());
                    builder.setPositiveButton("退出", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface arg0, int arg1) {
                            finish();
                        }
                    }).setNeutralButton("浏览器下载", new DialogInterface.OnClickListener() {//中性按钮 应用内下载失败可用它更新
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Uri uri = Uri.parse(webUrl);
                            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                            startActivity(intent);
                            if (NoIgnorable) {
                                finish(); //强制更新,点击后销毁应用
                            }else{
                                pd.dismiss(); //不强制更新,跳转到浏览器并销毁应用内下载失败的进度条
                            }
                        }
                    });
                    builder.create().show();
                }
                Looper.loop();
            }
        }.start();
    }

    /**
     * 安装apk
     */
    protected void installApk(File file) {
        Intent intent = new Intent();
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(Intent.ACTION_VIEW);

        if (Build.VERSION.SDK_INT >= 24) {
            Uri apkUri = FileProvider.getUriForFile(this, "com.example.ufcfans.fileprovider", file); //这里要写你程序的包名,已实验不可使用${applicationId}
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        } else {
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        }
        this.startActivity(intent);
    }


    /**
     * 从服务器获取apk文件的代码
     * 传入网址uri,进度条对象即可获得一个File文件
     * (要在子线程中执行哦)
     */
    public static File getFileFromServer(String uri, ProgressDialog pd) throws Exception {
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            URL url = new URL(uri);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            //获取到文件的大小
            pd.setMax(conn.getContentLength());  //字节的方式显示下载进度
            InputStream is = conn.getInputStream();
            //获取直链链接最后一个“/”后文字作为文件名,下载存储到手机
            File file = new File(Environment.getExternalStorageDirectory(), apkUrl.substring(apkUrl.lastIndexOf("/", apkUrl.lastIndexOf("")) + 1));
            FileOutputStream fos = new FileOutputStream(file);
            BufferedInputStream bis = new BufferedInputStream(is);
            byte[] buffer = new byte[1024];
            int len;
            int total = 0;
            while ((len = bis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
                total += len;
                //获取当前下载量
                pd.setProgress(total);//字节方式显示下载量
            }
            fos.close();
            bis.close();
            is.close();
            return file;
        } else {
            return null;
        }
    }

    /**
     * 权限的验证及处理,相关方法
     */
    private void getReadPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    ActivityCompat.requestPermissions(this,
                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                    Manifest.permission.READ_EXTERNAL_STORAGE}, 10001);
                } else {//没有则请求获取权限,示例权限是:存储权限,需要其他权限请更改或者替换
                    ActivityCompat.requestPermissions(this,
                            new String[]{
                                    Manifest.permission.READ_EXTERNAL_STORAGE,
                                    Manifest.permission.WRITE_EXTERNAL_STORAGE}, 10001);
                }
            } else {//如果已经获取到了权限则直接进行下一步操作
                Log.e(TAG, "全部权限已经授权成功");
            }
        }

    }

    /**
     * 一个或多个权限请求结果回调
     * 循环回调获取权限,除非勾选禁止后不再询问,之后提示用户引导用户去设置
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode) {
            case 10001:
                for (int i = 0; i < grantResults.length; i++) {
//                   如果拒绝获取权限
                    if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                        //判断是否勾选禁止后不再询问
                        boolean flag = ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i]);
                        if (flag) {
                            getReadPermissions();
                            return;//用户权限是一个一个的请求的,只要有拒绝,剩下的请求就可以停止,再次请求打开权限了
                        } else { // 勾选不再询问,并拒绝
                            Toast.makeText(this, "请到设置中打开权限", Toast.LENGTH_LONG).show();
                            return;
                        }
                    }
                }
                //Toast.makeText(this, "权限开启完成", Toast.LENGTH_LONG).show();
                break;
            default:
                break;
        }

    }

    /**
     * 忽略https的证书校验 的相关方法
     */
    public static void handleSSLHandshake() {
        try {
            TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }

                @Override
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            }};

            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        } catch (Exception ignored) {
        }
    }

至此,已完成对应用的版本控制更新,通过

更改html文件的versionVode控制更新,如:默认为1,改为2时,用户APP会弹出更新框。

 


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/660144.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

0001-TIPS-2020-hxp-kernel-rop : ret2user

目的 理解系统调用的过程&#xff1a;从用户态进入内核态&#xff0c;再从内核态返回用户态。细节见文末的参考了解一般性提权方法commit_creds(prepare_kernel_cred (0)); 环境搭建 下载 pwn 2020-kernel-rop wget https://2020.ctf.link/assets/files/kernel-rop-bf9c106…

说精神力量的词,愿力很神奇

说精神力量的词&#xff0c;愿力最神奇&#xff01; ​愿力&#xff0c;心力&#xff0c;精神&#xff0c;精 气 神&#xff0c;气 &#xff0c;能量 【能量】是个外来词 趣讲大白话&#xff1a;200天了&#xff0c;布道的愿力推动我 【趣讲信息科技200期】 ******************…

【换根DP】生活在树上

换根DP板子题 D-生活在树上_牛客小白月赛46 (nowcoder.com) 题意&#xff1a; 思路&#xff1a; 看数据范围是1e6且是统计问题&#xff0c;求的是对于每一个点的统计问题&#xff0c;那就逃不出是换根DP了 首先dfs1一次把树形DP求出来&#xff0c;然后再考虑换根 设dp[u]…

Wireshark抓包分析(ARP TCP DNS HTTP)

目录 一、ARP 二、DNS 三、TCP TCP的总过程&#xff1a; ​TCP三次握手&#xff1a; TCP四次挥手&#xff1a; 四、HTTP 一、ARP 1.ARP&#xff08;Address Resolution Protocol&#xff09;&#xff0c;是根据IP地址获取物理地址的一个TCP/IP协议。 我们要抓ARP 同网段内…

(学习日记)2023.06.15

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

0003-TIPS-2020-hxp-kernel-rop : bypass-KPTI-with-trampoline

KPTI KPTI描述内容摘录自ctf wiki KPTI 机制最初的主要目的是为了缓解 KASLR 的绕过以及 CPU 侧信道攻击。 在 KPTI 机制中&#xff0c;内核态空间的内存和用户态空间的内存的隔离进一步得到了增强。 内核态中的页表包括用户空间内存的页表和内核空间内存的页表。 用户态的页…

minikube 试炼

点我进入 minikube 试炼 今天我们先来尝试使用一下 minikube &#xff0c;可以进入到 https://kubernetes.io/zh/docs/tutorials/hello-minikube/ 页面上直接感受&#xff0c;或者通过如下指令&#xff0c;将 minikube 放入我们的服务器上面进行使用 简单安装 minikube Linu…

在Centos Stream 9上Docker的实操教程(六) - Docker Compose容器编排详解

在Centos Stream 9上Docker的实操教程 - Docker Compose容器编排详解 前言什么是Docker-Compose下载安装和卸载使用仓库安装手动安装卸载 docker compose常用命令项目实战构建SpringBoot项目编写Dockerfile文件编写Docker-Compose.yml文件 运行测试相关注意事项结语 前言 在了…

使用Pyinstall将PyQT5工程打包成.exe应用程序(包含图标一同打包)

1.首先安装pyinstaller。 pip install pyinstaller 2.PyQT5制作程序中使用到的ico等一系列图标文件&#xff0c;要先经过.qrc文件转成.py文件后&#xff0c;才可跟随打包文件一同打包。 首先创建一个.qrc文件&#xff0c;将图片文件全部写进去&#xff0c;例如: <RCC>&…

selenium 调用本地浏览器插件

本文所有教程及源码、软件仅为技术研究。不涉及计算机信息系统功能的删除、修改、增加、干扰,更不会影响计算机信息系统的正常运行。不得将代码用于非法用途,如侵立删!selenium 使用本地浏览器插件 环境 win10Python3.9selenium 4.10查看chrome配置文件路径 地址栏输入 ​​…

Python 请求分页

文章目录 什么是 Python 中的分页带有下一个按钮的 Python 分页没有下一个按钮的 Python 分页无限滚动的 Python 分页带有加载更多按钮的分页 在本文中&#xff0c;我们将了解分页以及如何克服 Python 中与分页相关的问题。 读完本文后&#xff0c;我们将能够了解 Python 分页以…

TensorHouse仓库介绍

目录 1 TensorHouse介绍 2 说明性例子 3模型列表 4基本组件 5方法 6参考 7后续计划 1 TensorHouse介绍 代码仓库&#xff1a;GitHub - ikatsov/tensor-house: A collection of reference machine learning and optimization models for enterprise operations: marketi…

插入排序-C语言实现

&#x1f970;前言 &#x1f354;在学数据结构的第一节课就知道了数据结构课程是要管理并且学会操作数据&#xff0c;当然操作数据首先想到的就是数据的排序&#xff0c;排过顺序的数据的使用价值才够大。前面我们学习了顺序表也学习了链表等等&#xff0c;这些就是储存数据的方…

哲学家就餐问题

哲学家就餐问题是一个著名的一类同步问题&#xff0c;在并发编程领域&#xff0c;常用来解释线程同步的问题。 问题描述&#xff1a;五位哲学家围坐在一张圆桌旁&#xff0c;每个哲学家面前有一碗米饭和一只筷子。这五个哲学家都是苦于无法同时持有两只筷子&#xff0c;因为只…

Autosar软件组件-Application Layer介绍和SWC(Software Component)类型

参考前文Autosar-软件架构,可知整个架构从上到下分层依次为:应用层(Application Software Layer),运行时环境(Runtime Environment,RTE),基础软件层(Basic Software Layer,BSW),微控制器(Microcontroller)。 Application Layer由各种AUTOSAR Software Componen…

【备战秋招】每日一题:华东师范大学保研机试-2022-整数排序

为了更好的阅读体检&#xff0c;可以查看我的算法学习博客华东师范大学保研机试-2022-整数排序 题目内容 输入若干个int类型整数&#xff0c;将整数按照位数由大到小排序&#xff0c;如果位数相同&#xff0c;则按照整数本身从小到大排序。 例如, 输入:10 -3 1 23 89 100 9…

【第四次】21级计科计算机组成原理课外练习

【第四次】21级计科计算机组成原理课外练习 一、判断题二、单选题三、多选题四、填空题五、程序填空题 一、判断题 1-1 设机器数字长8位&#xff08;含1位符号位&#xff09;&#xff0c;若机器数BAH为原码&#xff0c;算术右移一位得到的结果为 9D H 。 T F 1-2 ALU中采用双…

spring 反射,BigDecimal,自定义注解的使用(aop)

反射 利用反射调用它类中的属性和方法时&#xff0c;无视修饰符。 获取Class类的对象&#xff08;三种方式&#xff09; Class.forName(“全类名”) &#xff08;推荐使用&#xff09;类名.class对象.getClass() 反射获取构造方法Constructor<?>[] getConstructors()…

Android 逆向之脱壳实战篇

作者&#xff1a;37手游安卓团队 前言 这篇文章比较干&#xff0c;比较偏实战&#xff0c;看之前建议先喝足水&#xff0c;慎入。 在学脱壳之前&#xff0c;我们先来复习一下&#xff0c;什么时候是加固&#xff1f; 加固本质上就是对 dex 文件进行加壳处理&#xff0c;让一些…

信号三大阶段之储存信号

目录 一、 信号三大阶段 二、信号储存相关概念 三、 理解概念 四、信号储存原理 五、信号集操作函数 一、 信号三大阶段 二、信号储存相关概念 实际执行信号的过程被称为信号递达&#xff08;Delivery&#xff09;。信号从产生到递达之间的状态被称为信号未决&#xff08;…