国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

AndroidStudio 實現(xiàn)APP版本自動更新(內(nèi)部更新,不涉及第三方市場)

這篇具有很好參考價值的文章主要介紹了AndroidStudio 實現(xiàn)APP版本自動更新(內(nèi)部更新,不涉及第三方市場)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

實現(xiàn)效果圖

android 第三方更新服務,Java,java,android,開發(fā)語言
android 第三方更新服務,Java,java,android,開發(fā)語言文章來源地址http://www.zghlxwxcb.cn/news/detail-592624.html

調(diào)用自動更新

  //Activity創(chuàng)建或者從被覆蓋、后臺重新回到前臺時被調(diào)用
    @Override
    protected void onResume() {
        super.onResume();
        //查詢APP版本
        selectAPPVesion();
    }

1、獲取更新版本號

    private int getVersion(final SysNotice sysNotice, int vision) {

        if (sysNotice == null) {
            return 0;
        }
        //網(wǎng)絡請求獲取當前版本號和下載鏈接
        //實際操作是從服務器獲取
        String sdcardRoot = getExternalFilesDir(null) + File.separator + "test/apk";
        String apkSavePath = sdcardRoot + "/1.apk";
        String newversion = sysNotice.getVersion();//更新新的版本號
        String content = sysNotice.getNoticeContent();//更新內(nèi)容
        String url = "127.0.0.1:8080" + Interface.APPapk;//安裝包下載地址

        double newversioncode = Double
                .parseDouble(newversion);
        int cc = (int) (newversioncode);

        if (cc != vision) {
            if (vision < cc) {
                System.out.println(newversion + "v"
                        + vision);
                // 版本號不同
                ShowDialog(vision, newversion, sysNotice, url);
            }
            return 1;
        } else {
            return 0;
        }
    }

2、彈出彈窗升級系統(tǒng)

    private void ShowDialog(int vision, String newversion, SysNotice sysNotice,
                            final String url) {
        new android.app.AlertDialog.Builder(this)
                .setTitle(sysNotice.getNoticeTitle())
                .setMessage(Html.fromHtml(sysNotice.getNoticeContent()).toString())
                .setPositiveButton("更新", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        pBar = new CommonProgressDialog(MainActivity.this);
                        pBar.setCanceledOnTouchOutside(false);
                        pBar.setTitle("正在下載");
                        pBar.setCustomTitle(LayoutInflater.from(
                                MainActivity.this).inflate(
                                R.layout.title_dialog, null));
                        pBar.setMessage("正在下載");
                        pBar.setIndeterminate(true);
                        pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                        pBar.setCancelable(true);
                        // downFile(URLData.DOWNLOAD_URL);
                        final DownloadTask downloadTask = new DownloadTask(
                                MainActivity.this);
                        downloadTask.execute(url);
                        pBar.setOnCancelListener(new DialogInterface.OnCancelListener() {
                            @Override
                            public void onCancel(DialogInterface dialog) {
                                downloadTask.cancel(true);
                            }
                        });
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                })
                .show();
    }

3、下載應用

 /**
     * 下載應用
     *
     * @author Administrator
     */
    class DownloadTask extends AsyncTask<String, Integer, String> {

        private Context context;
        private PowerManager.WakeLock mWakeLock;

        public DownloadTask(Context context) {
            this.context = context;
        }

        @Override
        protected String doInBackground(String... sUrl) {
            InputStream input = null;
            OutputStream output = null;
            HttpURLConnection connection = null;
            File file = null;
            try {
                URL url = new URL(sUrl[0]);
                connection = (HttpURLConnection) url.openConnection();
                connection.connect();
                // expect HTTP 200 OK, so we don't mistakenly save error
                // report
                // instead of the file
                if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                    return "Server returned HTTP "
                            + connection.getResponseCode() + " "
                            + connection.getResponseMessage();
                }
                // this will be useful to display download percentage
                // might be -1: server did not report the length
                int fileLength = connection.getContentLength();
                String sdcardRoot = getExternalFilesDir(null) + File.separator + "test/apk";
                final String apkSavePath = sdcardRoot + "/1.apk";
                System.err.println(apkSavePath);

                file = new File(apkSavePath);

                if (!file.exists()) {
                    // 判斷父文件夾是否存在
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                }

                input = connection.getInputStream();
                output = new FileOutputStream(file);
                byte data[] = new byte[4096];
                long total = 0;
                int count;
                while ((count = input.read(data)) != -1) {
                    // allow canceling with back button
                    if (isCancelled()) {
                        input.close();
                        return null;
                    }
                    total += count;
                    // publishing the progress....
                    if (fileLength > 0) // only if total length is known
                        publishProgress((int) (total * 100 / fileLength));
                    output.write(data, 0, count);

                }
            } catch (Exception e) {
                System.out.println(e.toString());
                return e.toString();

            } finally {
                try {
                    if (output != null)
                        output.close();
                    if (input != null)
                        input.close();
                } catch (IOException ignored) {
                }
                if (connection != null)
                    connection.disconnect();
            }
            return null;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // take CPU lock to prevent CPU from going off if the user
            // presses the power button during download
            PowerManager pm = (PowerManager) context
                    .getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                    getClass().getName());
            mWakeLock.acquire();
            pBar.show();
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            super.onProgressUpdate(progress);
            // if we get here, length is known, now set indeterminate to false
            pBar.setIndeterminate(false);
            pBar.setMax(100);
            pBar.setProgress(progress[0]);
        }

        @Override
        protected void onPostExecute(String result) {
            mWakeLock.release();
            pBar.dismiss();
            if (result != null) {
                // 申請多個權(quán)限。
                AndPermission.with(MainActivity.this)
                        .requestCode(REQUEST_CODE_PERMISSION_SD)
                        .permission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
                        // rationale作用是:用戶拒絕一次權(quán)限,再次申請時先征求用戶同意,再打開授權(quán)對話框,避免用戶勾選不再提示。
                        .rationale(rationaleListener
                        )
                        .send();


                Toast.makeText(context, "您未打開SD卡權(quán)限" + result, Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(context, "File downloaded",
                        Toast.LENGTH_SHORT)
                        .show();
                update();
            }

//            }
        }
    }

4、解決權(quán)限獲取

  private static final int REQUEST_CODE_PERMISSION_SD = 101;

    private static final int REQUEST_CODE_SETTING = 300;
    private RationaleListener rationaleListener = new RationaleListener() {
        @Override
        public void showRequestPermissionRationale(int requestCode, final Rationale rationale) {
            // 這里使用自定義對話框,如果不想自定義,用AndPermission默認對話框:
            // AndPermission.rationaleDialog(Context, Rationale).show();

            // 自定義對話框。
            com.yanzhenjie.alertdialog.AlertDialog.build(MainActivity.this)
                    .setTitle(R.string.title_dialog)
                    .setMessage(R.string.message_permission_rationale)
                    .setPositiveButton(R.string.btn_dialog_yes_permission, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();
                            rationale.resume();
                        }
                    })

                    .setNegativeButton(R.string.btn_dialog_no_permission, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();
                            rationale.cancel();
                        }
                    })
                    .show();
        }
    };

    //        ----------------------------------SD權(quán)限----------------------------------//
    @PermissionYes(REQUEST_CODE_PERMISSION_SD)
    private void getMultiYes(List<String> grantedPermissions) {
        Toast.makeText(this, R.string.message_post_succeed, Toast.LENGTH_SHORT).show();
    }

    @PermissionNo(REQUEST_CODE_PERMISSION_SD)
    private void getMultiNo(List<String> deniedPermissions) {
        Toast.makeText(this, R.string.message_post_failed, Toast.LENGTH_SHORT).show();

        // 用戶否勾選了不再提示并且拒絕了權(quán)限,那么提示用戶到設置中授權(quán)。
        if (AndPermission.hasAlwaysDeniedPermission(this, deniedPermissions)) {
            AndPermission.defaultSettingDialog(this, REQUEST_CODE_SETTING)
                    .setTitle(R.string.title_dialog)
                    .setMessage(R.string.message_permission_failed)
                    .setPositiveButton(R.string.btn_dialog_yes_permission)
                    .setNegativeButton(R.string.btn_dialog_no_permission, null)
                    .show();

            // 更多自定dialog,請看上面。
        }
    }

    //----------------------------------權(quán)限回調(diào)處理----------------------------------//

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
            grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        /**
         * 轉(zhuǎn)給AndPermission分析結(jié)果。
         *
         * @param object     要接受結(jié)果的Activity、Fragment。
         * @param requestCode  請求碼。
         * @param permissions  權(quán)限數(shù)組,一個或者多個。
         * @param grantResults 請求結(jié)果。
         */
        AndPermission.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case REQUEST_CODE_SETTING: {
                Toast.makeText(this, R.string.message_setting_back, Toast.LENGTH_LONG).show();
                //設置成功,再次請求更新
                getVersion(sysNotice, Tools.getVersion(MainActivity.this));
                break;
            }
        }
    }

    private void update() {
        //安裝應用
        //獲取SD卡的根路徑
        String sdcardRoot = getExternalFilesDir(null) + File.separator + "test/apk";
        final String apkSavePath = sdcardRoot + "/1.apk";
        System.err.println(apkSavePath);
        //安裝應用
        Intent intent = new Intent(Intent.ACTION_VIEW);
        File apkFile = new File(apkSavePath);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Uri uri = FileProvider.getUriForFile(MainActivity.this, this.getPackageName() + ".fileprovider", apkFile);
            intent.setDataAndType(uri, "application/vnd.android.package-archive");
            startActivity(intent);
        } else {
            //  intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
        }

    }

5、調(diào)用后端接口,查詢APP版本和后端發(fā)布公告版本

    public void selectAPPVesion() {
        try {
            OkHttpTool.httpPost("127.0.0.1:8080" + Interface.selectAPPVesion, null, null, new OkHttpTool.ResponseCallback() {
                @Override
                public void onResponse(final boolean isSuccess, final int responseCode, final String response, Exception exception) {
                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (isSuccess && responseCode == 200) {
                                if (!TextUtils.isEmpty(response)) {
                                    //得到resultBean的數(shù)據(jù)
                                    JSONObject jsonObject = JSON.parseObject(response);
                                    Integer code = jsonObject.getInteger("code");
                                    if (code.equals(200)) {
                                        sysNotice = JSON.parseObject(jsonObject.getString("data"), SysNotice.class);
                                    }
                                }
                            }
                            // 獲取本版本號,是否更新
                            int vision = Tools.getVersion(MainActivity.this);
                            int version = getVersion(sysNotice, vision);
                            if (version == 0) {
                                initseifLogin();
                            }
                        }
                    });
                }
            });

        } catch (Exception e) {
            Intent intent = new Intent(MainActivity.this, Configure_Activity.class);
            intent.putExtra("isLogin", "false");
            startActivity(intent);
            Toast.makeText(MainActivity.this, "Invalid URL port", Toast.LENGTH_SHORT).show();
        }

    }

6、工具封裝Tools–獲取APP版本號

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
/**
 *
 */
public class Tools {
    /**
     * 2 * 獲取版本號 3 * @return 當前應用的版本號 4
     */
    public static int getVersion(Context context) {
        try {
            PackageManager manager = context.getPackageManager();
            PackageInfo info = manager.getPackageInfo(context.getPackageName(),
                    0);
            String version = info.versionName;
            int versioncode = info.versionCode;
            return versioncode;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}

7、網(wǎng)絡請求封裝–OkHttpTool

    //網(wǎng)絡請求
    implementation 'com.squareup.okhttp3:okhttp:3.11.0'

import android.util.Log;

import androidx.annotation.NonNull;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class OkHttpTool {

    private static String TAG = "OkHttpTool";

    private static final OkHttpClient myOkHttpClient =  new OkHttpClient.Builder()
            .connectTimeout(15, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            //添加cookie處理
            .cookieJar(new CookieJar() {//這里是設置cookie的,但是并沒有做持久化處理;只是把cookie保存在內(nèi)存中
                private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();

                @Override
                public void saveFromResponse(@NonNull HttpUrl url, @NonNull List<Cookie> cookies) {
                    cookieStore.put(url.host(), cookies);
                }
                @Override
                public List<Cookie> loadForRequest(@NonNull HttpUrl url) {
                    List<Cookie> cookies = cookieStore.get(url.host());
                    return cookies != null ? cookies : new ArrayList<Cookie>();
                }
            })
            //添加日志處理攔截器
            .addInterceptor(new Interceptor() {

                @Override
                public okhttp3.Response intercept(@NonNull Chain chain) throws IOException {
                    Request request = chain.request();
                    long startTime = System.currentTimeMillis();
                    okhttp3.Response response = chain.proceed(chain.request());
                    long endTime = System.currentTimeMillis();
                    long duration=endTime-startTime;
                    okhttp3.MediaType mediaType = response.body().contentType();
                    String content = response.body().string();
                    Log.d(TAG,"\n");
                    Log.d(TAG,"----------Start----------------");
                    Log.d(TAG, "| "+request.toString());
                    String method=request.method();
                    if("POST".equals(method)){
                        StringBuilder sb = new StringBuilder();
                        if (request.body() instanceof FormBody) {
                            FormBody body = (FormBody) request.body();
                            for (int i = 0; i < body.size(); i++) {
                                sb.append(body.encodedName(i) + "=" + body.encodedValue(i) + ",");
                            }
                            if (sb.length()>0){
                                //在參數(shù)不為空的情況下處理最后的 “,”
                                sb.delete(sb.length() - 1, sb.length());
                            }
                            Log.d(TAG, "| RequestParams:{"+sb.toString()+"}");
                        }
                    }
                    Log.d(TAG, "| Response:" + content);
                    Log.d(TAG,"----------End:"+duration+"毫秒----------");
                    return response.newBuilder()
                            .body(okhttp3.ResponseBody.create(mediaType, content))
                            .build();
                }
            })
            .build();

    public static void httpGet(String url, Map<String, Object> parameters, Map<String, Object> headers, ResponseCallback responseCallback){
        Request request=createGetRequest(url,parameters,headers);
        doRequest(request,responseCallback);
    }

    public static void httpPost(String url, Map<String, Object> parameters, Map<String, Object> headers, ResponseCallback responseCallback){
        Request request=createPostRequest(url,parameters,headers);
        doRequest(request,responseCallback);
    }

    public static void httpPostJson(String url, String json, Map<String, Object> headers, ResponseCallback responseCallback){
        Request request=createPostRequestJson(url,json,headers);
        doRequest(request,responseCallback);
    }
    public static void httpPostWithFile(String url, Map<String, Object> parameters, Map<String, File> files, Map<String, Object> headers, ResponseCallback responseCallback) {
        Request request=createPostRequestWithFile(url,parameters,files,headers);
        doRequest(request,responseCallback);
    }


    public static Request createGetRequest(String url, Map<String, Object> parameters, Map<String, Object> headers) {
        StringBuilder urlBuilder = new StringBuilder();
        urlBuilder.append(url);
        if (url.indexOf('?') <= -1) {
            //未拼接參數(shù)
            urlBuilder.append("?");
        }
        if (parameters != null) {
            for (Map.Entry<String, Object> entry : parameters.entrySet()) {
                urlBuilder.append("&");
                urlBuilder.append(entry.getKey());
                urlBuilder.append("=");
                urlBuilder.append(entry.getValue().toString());
            }
        }
        return getBaseRequest(headers).url(urlBuilder.toString()).build();
    }

    public static Request createPostRequest(String url, Map<String, Object> parameters, Map<String, Object> headers) {
        FormBody.Builder builder = new FormBody.Builder(Charset.forName("UTF-8"));
        if (parameters != null) {
            for (Map.Entry<String, Object> entry : parameters.entrySet()) {
                builder.add(entry.getKey(), entry.getValue().toString());
            }
        }
        FormBody formBody = builder.build();
        return getBaseRequest(headers).url(url).post(formBody).build();
    }

    public static Request createPostRequestJson(String url, String json, Map<String, Object> headers) {
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(JSON, json);
        return getBaseRequest(headers).url(url).post(body).build();
    }

    public static Request createPostRequestWithFile(String url, Map<String, Object> parameters, Map<String, File> files, Map<String, Object> headers) {
        // form 表單形式上傳
        MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (files != null) {
            for (Map.Entry<String, File> fileEntry : files.entrySet()) {
                File file = fileEntry.getValue();
                if (file != null) {
                    // MediaType.parse() 里面是上傳的文件類型。
                    RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"), file);
                    String filename = file.getName();
                    // 參數(shù)分別為, 請求key ,文件名稱 , RequestBody
                    requestBody.addFormDataPart(fileEntry.getKey(), filename, body);
                }
            }
        }
        if (parameters != null) {
            // map 里面是請求中所需要的 key 和 value
            for (Map.Entry<String, Object> entry : parameters.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue().toString();
                requestBody.addFormDataPart(key, value);
            }
        }
        return getBaseRequest(headers).url(url).post(requestBody.build()).build();
    }

    private static void doRequest(final Request request, final ResponseCallback responseCallback) {
        //使用okhttp3的異步請求
        myOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                //回調(diào)
                Log.e(TAG,e.getMessage());
                responseCallback.onResponse(false, -1, null, e);
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                int responseCode = response.code();//獲取響應碼
                ResponseBody responseBody = response.body();//獲取 ResponseBody
                if (response.isSuccessful() && responseBody != null) {
                    String strResponse = responseBody.string();
                    //回調(diào)
                    responseCallback.onResponse(true, responseCode, strResponse, null);
                } else {
                    //回調(diào)
                    responseCallback.onResponse(false, responseCode, null, null);
                }
            }
        });
    }

    private static Request.Builder getBaseRequest(Map<String, Object> headers) {
        Request.Builder builder = new Request.Builder();
        builder.addHeader("client", "Android");
        if (headers != null) {
        // map 里面是請求中所需要的 key 和 value
        for (Map.Entry<String, Object> entry : headers.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue().toString();
            builder.addHeader(key, value);
        }
        }
        return builder;
    }


    public interface ResponseCallback {
        void onResponse(boolean isSuccess, int responseCode, String response, Exception exception);
    }


}

8、后端下載接口

 /**
     * 本地資源通用下載
     */
    @GetMapping("/api/download/APPapk")
    public void APPapk(HttpServletRequest request, HttpServletResponse response)
            throws Exception
    {

        File dir = new File("E:\\appPath\\");
        String[] children = dir.list();
        if (children == null) {
            System.out.println("該目錄不存在");
            throw new Exception(StringUtils.format("該更新APK不存在"));
        }
        else {
            for (int i = 0; i < children.length; i++) {
                String filename = children[i];
                if(filename.contains(".apk")){
                    try
                    {
                        // 數(shù)據(jù)庫資源地址
                        String downloadPath = dir.getAbsolutePath()+File.separator+filename;
                        // 下載名稱
                        response.setContentLengthLong((int) new File(dir.getAbsolutePath()+File.separator+filename).length());
                        response.setContentLength((int) new File(dir.getAbsolutePath()+File.separator+filename).length());
                        response.setHeader("Content-Length", String.valueOf(new File(dir.getAbsolutePath()+File.separator+filename).length()));
                        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
                        FileUtils.setAttachmentResponseHeader(response, filename);
                        FileUtils.writeBytes(downloadPath, response.getOutputStream());
                    }
                    catch (Exception e)
                    {
                        log.error("下載文件失敗", e);
                    }
                    return;
                }
            }
        }

    }

9、查詢后端發(fā)布公告是否更新APP

 /**
     * 查找app版本信息   select  * from sys_notice  order by notice_id desc Limit 1
     * 查詢最后一條數(shù)據(jù) 
     */
    @PostMapping("selectAPPVesion")
    public AjaxResult selectAPPVesion() {
        SysNotice sysNoticePa=new SysNotice();
        SysNotice sysNotice = noticeMapper.selectAPPVesion(sysNoticePa);
        return AjaxResult.success(sysNotice);
    }

到了這里,關于AndroidStudio 實現(xiàn)APP版本自動更新(內(nèi)部更新,不涉及第三方市場)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • uniapp校驗app版本并更新

    最近用uniapp寫了一個安卓殼子做app,遇到一個需求,校驗app版本并更新 通過對比線上版本號和app自己的版本號的差異,喚起更新彈窗 相關代碼 App.vue pages下的upgrade? ??index.vue pages下的upgrade? ??upgrade.js pages.json?

    2024年02月20日
    瀏覽(7)
  • 【Android】-- 如何對APP版本控制/更新?

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

    目錄 一、 前提準備 1、獲取服務器 2、使用工具操作云服務器 ?二、Json格式網(wǎng)頁 ?三、創(chuàng)建file_paths.xml及修改AndroidManifest.xml 四、在java代碼加入更新檢測代碼 效果如圖: ??????? 可以強制更新和非強制更新,和瀏覽器下載安裝包。 ????????首先去獲取云服務器,如:阿

    2024年02月12日
    瀏覽(24)
  • iOS App的上架和版本更新流程

    iOS App的上架和版本更新流程

    作為一名iOSDeveloper,把開發(fā)出來的App上傳到App Store是必要的。下面就來詳細講解一下具體流程步驟。 一個已付費的開發(fā)者賬號(賬號類型分為個人(Individual)、公司(Company)、企業(yè)(Enterprise)、高校(University)四種類型,每年資費分別為$99、$99、$299、免費。)。 一個已經(jīng)

    2024年02月11日
    瀏覽(24)
  • uniapp 實戰(zhàn) -- app 的自動升級更新(含生成 app 發(fā)布頁)

    uniapp 實戰(zhàn) -- app 的自動升級更新(含生成 app 發(fā)布頁)

    uniapp 提供了 App升級中心 uni-upgrade-center ,可以便捷實現(xiàn)app 的自動升級更新,具體編碼和配置如下: https://ext.dcloud.net.cn/plugin?id=4542 (不要配在第一項) pages/index/index.vue https://blog.csdn.net/weixin_41192489/article/details/135551800 本范例中,版本配置為1.0.1版 詳見 https://blog.csdn.net/weixi

    2024年02月02日
    瀏覽(23)
  • 前端項目部署自動檢測更新后通知用戶刷新頁面(前端實現(xiàn),技術(shù)框架vue、js、webpack)——方案一:編譯項目時動態(tài)生成一個記錄版本號的文件

    前端項目部署自動檢測更新后通知用戶刷新頁面(前端實現(xiàn),技術(shù)框架vue、js、webpack)——方案一:編譯項目時動態(tài)生成一個記錄版本號的文件

    當我們重新部署前端項目的時候,如果用戶一直停留在頁面上并未刷新使用,會存在功能使用差異性的問題,因此,當前端部署項目后,需要提醒用戶有去重新加載頁面。 vue、js、webpack 編譯項目時動態(tài)生成一個記錄版本號的文件 輪詢(20s、自己設定時間)這個文件,判斷版

    2024年02月02日
    瀏覽(56)
  • 【Android】app應用內(nèi)版本更新升級(DownloadManager下載,適配Android6.0以上所有版本)

    【Android】app應用內(nèi)版本更新升級(DownloadManager下載,適配Android6.0以上所有版本)

    版本的升級和更新是一個線上App所必備的功能,App的升級安裝包主要通過 應用商店 或者 應用內(nèi)下載 兩種方式獲得,大部分app這兩種方式都會具備,應用商店只需要上傳對應平臺審核通過即可,而應用內(nèi)更新一般是通過以下幾種方式: 1.集成第三方庫如 appupdateX、bugly 的更新

    2024年02月11日
    瀏覽(32)
  • 打包時,自動更新版本號,清空緩存

    打包時,自動更新版本號,清空緩存

    1.創(chuàng)建 addVersion.js 文件 2.修改package.json 文件 serve 執(zhí)行為測試用的,看版本是否生效 打包更新版本號,只需配置 build 相關指令即可 main.js 文件中添加 清除緩存功能 ok 完成以上執(zhí)行 查看 package.json 中是否改變 ,結(jié)束

    2024年02月02日
    瀏覽(17)
  • uni.app如何檢測小程序版本更新以及上線后如何關閉全局打印

    uni.app如何檢測小程序版本更新以及上線后如何關閉全局打印

    App.vue 入口文件中 添加如下代碼 微信小程序 測試 重新編譯后 即可看到以下內(nèi)容 在main.js中 加上以下代碼

    2024年02月07日
    瀏覽(24)
  • 【Selenium】chromedriver最新版本與Chrome自動更新版本不匹配問題

    【Selenium】chromedriver最新版本與Chrome自動更新版本不匹配問題

    使用Selenium時需要下載chromedriver 1、首先查看我的Chrome瀏覽器版本已自動更新到116: 2、查找與之對應的chromedriver版本:http://chromedriver.storage.googleapis.com/index.html 發(fā)現(xiàn)最新版本只到114: chromedriver與Chrome版本不匹配且沒有匹配最新Chrome版本的chromedriver。 因此考慮降級Chrome版本且

    2024年02月16日
    瀏覽(21)
  • 360安全路由怎么關閉自動更新升級保留出廠版本

    360安全路由默認在聯(lián)網(wǎng)情況下,會自動進行固件版本更新升級,如果我們需要保留出廠版本,避免當有新版本時,被自動升級的話,該如何操作呢?下面小編詳細介紹一下360安全路由關閉自動升級更新系統(tǒng)方法。 360安全路由怎么關閉自動更新升級 一、登陸360安全路由后臺管理

    2024年02月07日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包