android apk靜默安裝

来源:http://www.cnblogs.com/xiaoxiaing/archive/2016/04/07/5362452.html
-Advertisement-
Play Games

轉載請註明出處:http://blog.csdn.net/guolin_blog/article/details/47803149 之前有很多朋友都問過我,在Android系統中怎樣才能實現靜默安裝呢?所謂的靜默安裝,就是不用彈出系統的安裝界面,在不影響用戶任何操作的情況下不知不覺地將程式裝好。雖說 ...


轉載請註明出處:http://blog.csdn.net/guolin_blog/article/details/47803149

之前有很多朋友都問過我,在Android系統中怎樣才能實現靜默安裝呢?所謂的靜默安裝,就是不用彈出系統的安裝界面,在不影響用戶任何操作的情況下不知不覺地將程式裝好。雖說這種方式看上去不打攪用戶,但是卻存在著一個問題,因為Android系統會在安裝界面當中把程式所聲明的許可權展示給用戶看,用戶來評估一下這些許可權然後決定是否要安裝該程式,但如果使用了靜默安裝的方式,也就沒有地方讓用戶看許可權了,相當於用戶被動接受了這些許可權。在Android官方看來,這顯示是一種非常危險的行為,因此靜默安裝這一行為系統是不會開放給開發者的。

但是總是彈出一個安裝對話框確實是一種體驗比較差的行為,這一點Google自己也意識到了,因此Android系統對自家的Google Play商店開放了靜默安裝許可權,也就是說所有從Google Play上下載的應用都可以不用彈出安裝對話框了。這一點充分說明瞭擁有許可權的重要性,自家的系統想怎麼改就怎麼改。借鑒Google的做法,很多國內的手機廠商也採用了類似的處理方式,比如說小米手機在小米商店中下載應用也是不需要彈出安裝對話框的,因為小米可以在MIUI中對Android系統進行各種定製。因此,如果我們只是做一個普通的應用,其實不太需要考慮靜默安裝這個功能,因為我們只需要將應用上架到相應的商店當中,就會自動擁有靜默安裝的功能。

但是如果我們想要做的也是一個類似於商店的平臺呢?比如說像360手機助手,它廣泛安裝於各種各樣的手機上,但都是作為一個普通的應用存在的,而沒有Google或小米這樣的特殊許可權,那360手機助手應該怎樣做到更好的安裝體驗呢?為此360手機助手提供了兩種方案, 秒裝(需ROOT許可權)和智能安裝,如下圖示:

因此,今天我們就模仿一下360手機助手的實現方式,來給大家提供一套靜默安裝的解決方案。

一、秒裝

所謂的秒裝其實就是需要ROOT許可權的靜默安裝,其實靜默安裝的原理很簡單,就是調用Android系統的pm install命令就可以了,但關鍵的問題就在於,pm命令系統是不授予我們許可權調用的,因此只能在擁有ROOT許可權的手機上去申請許可權才行。

下麵我們開始動手,新建一個InstallTest項目,然後創建一個SilentInstall類作為靜默安裝功能的實現類,代碼如下所示:

[java] view plain copy  
  1. /** 
  2.  * 靜默安裝的實現類,調用install()方法執行具體的靜默安裝邏輯。 
  3.  * 原文地址:http://blog.csdn.net/guolin_blog/article/details/47803149 
  4.  * @author guolin 
  5.  * @since 2015/12/7 
  6.  */  
  7. public class SilentInstall {  
  8.   
  9.     /** 
  10.      * 執行具體的靜默安裝邏輯,需要手機ROOT。 
  11.      * @param apkPath 
  12.      *          要安裝的apk文件的路徑 
  13.      * @return 安裝成功返回true,安裝失敗返回false。 
  14.      */  
  15.     public boolean install(String apkPath) {  
  16.         boolean result = false;  
  17.         DataOutputStream dataOutputStream = null;  
  18.         BufferedReader errorStream = null;  
  19.         try {  
  20.             // 申請su許可權  
  21.             Process process = Runtime.getRuntime().exec("su");  
  22.             dataOutputStream = new DataOutputStream(process.getOutputStream());  
  23.             // 執行pm install命令  
  24.             String command = "pm install -r " + apkPath + "\n";  
  25.             dataOutputStream.write(command.getBytes(Charset.forName("utf-8")));  
  26.             dataOutputStream.flush();  
  27.             dataOutputStream.writeBytes("exit\n");  
  28.             dataOutputStream.flush();  
  29.             process.waitFor();  
  30.             errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));  
  31.             String msg = "";  
  32.             String line;  
  33.             // 讀取命令的執行結果  
  34.             while ((line = errorStream.readLine()) != null) {  
  35.                 msg += line;  
  36.             }  
  37.             Log.d("TAG", "install msg is " + msg);  
  38.             // 如果執行結果中包含Failure字樣就認為是安裝失敗,否則就認為安裝成功  
  39.             if (!msg.contains("Failure")) {  
  40.                 result = true;  
  41.             }  
  42.         } catch (Exception e) {  
  43.             Log.e("TAG", e.getMessage(), e);  
  44.         } finally {  
  45.             try {  
  46.                 if (dataOutputStream != null) {  
  47.                     dataOutputStream.close();  
  48.                 }  
  49.                 if (errorStream != null) {  
  50.                     errorStream.close();  
  51.                 }  
  52.             } catch (IOException e) {  
  53.                 Log.e("TAG", e.getMessage(), e);  
  54.             }  
  55.         }  
  56.         return result;  
  57.     }  
  58.   
  59. }  

可以看到,SilentInstall類中只有一個install()方法,所有靜默安裝的邏輯都在這個方法中了,那麼我們具體來看一下這個方法。首先在第21行調用了Runtime.getRuntime().exec("su")方法,在這裡先申請ROOT許可權,不然的話後面的操作都將失敗。然後在第24行開始組裝靜默安裝命令,命令的格式就是pm install -r <apk路徑>,-r參數表示如果要安裝的apk已經存在了就覆蓋安裝的意思,apk路徑是作為方法參數傳入的。接下來的幾行就是執行上述命令的過程,註意安裝這個過程是同步的,因此我們在下麵調用了process.waitFor()方法,即安裝要多久,我們就要在這裡等多久。等待結束之後說明安裝過程結束了,接下來我們要去讀取安裝的結果併進行解析,解析的邏輯也很簡單,如果安裝結果中包含Failure字樣就說明安裝失敗,反之則說明安裝成功。

 

整個方法還是非常簡單易懂的,下麵我們就來搭建調用這個方法的環境。修改activity_main.xml中的代碼,如下所示:

[html] view plain copy  
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:orientation="vertical"  
  7.     android:paddingBottom="@dimen/activity_vertical_margin"  
  8.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  9.     android:paddingRight="@dimen/activity_horizontal_margin"  
  10.     android:paddingTop="@dimen/activity_vertical_margin"  
  11.     tools:context="com.example.installtest.MainActivity">  
  12.   
  13.     <LinearLayout  
  14.         android:layout_width="match_parent"  
  15.         android:layout_height="wrap_content">  
  16.   
  17.         <Button  
  18.             android:layout_width="wrap_content"  
  19.             android:layout_height="wrap_content"  
  20.             android:onClick="onChooseApkFile"  
  21.             android:text="選擇安裝包" />  
  22.   
  23.         <TextView  
  24.             android:id="@+id/apkPathText"  
  25.             android:layout_width="0dp"  
  26.             android:layout_height="wrap_content"  
  27.             android:layout_weight="1"  
  28.             android:layout_gravity="center_vertical"  
  29.             />  
  30.   
  31.     </LinearLayout>  
  32.   
  33.   
  34.     <View  
  35.         android:layout_width="match_parent"  
  36.         android:layout_height="1dp"  
  37.         android:background="@android:color/darker_gray" />  
  38.   
  39.     <Button  
  40.         android:layout_width="wrap_content"  
  41.         android:layout_height="wrap_content"  
  42.         android:onClick="onSilentInstall"  
  43.         android:text="秒裝" />  
  44.   
  45.     <View  
  46.         android:layout_width="match_parent"  
  47.         android:layout_height="1dp"  
  48.         android:background="@android:color/darker_gray" />  
  49.   
  50.     <Button  
  51.         android:layout_width="wrap_content"  
  52.         android:layout_height="wrap_content"  
  53.         android:onClick="onForwardToAccessibility"  
  54.         android:text="開啟智能安裝服務" />  
  55.   
  56.     <Button  
  57.         android:layout_width="wrap_content"  
  58.         android:layout_height="wrap_content"  
  59.         android:onClick="onSmartInstall"  
  60.         android:text="智能安裝" />  
  61. </LinearLayout>  

這裡我們先將程式的主界面確定好,主界面上擁有四個按鈕,第一個按鈕用於選擇apk文件的,第二個按鈕用於開始秒裝,第三個按鈕用於開啟智能安裝服務,第四個按鈕用於開始智能安裝,這裡我們暫時只能用到前兩個按鈕。那麼調用SilentInstall的install()方法需要傳入apk路徑,因此我們需要先把文件選擇器的功能實現好,新建activity_file_explorer.xml和list_item.xml作為文件選擇器的佈局文件,代碼分別如下所示:

[html] view plain copy  
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent">  
  6.   
  7.     <ListView  
  8.         android:id="@+id/list_view"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="match_parent"  
  11.          />  
  12.   
  13. </LinearLayout>  
[html] view plain copy  
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="wrap_content"  
  6.     android:padding="4dp"  
  7.     android:orientation="horizontal">  
  8.   
  9.     <ImageView android:id="@+id/img"  
  10.         android:layout_width="32dp"  
  11.         android:layout_margin="4dp"  
  12.         android:layout_gravity="center_vertical"  
  13.         android:layout_height="32dp"/>  
  14.   
  15.   
  16.     <TextView android:id="@+id/name"  
  17.         android:textSize="18sp"  
  18.         android:textStyle="bold"  
  19.         android:layout_width="match_parent"  
  20.         android:gravity="center_vertical"  
  21.         android:layout_height="50dp"/>  
  22.   
  23. </LinearLayout>  

然後新建FileExplorerActivity作為文件選擇器的Activity,代碼如下:

[java] view plain copy  
  1. public class FileExplorerActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {  
  2.   
  3.     ListView listView;  
  4.     SimpleAdapter adapter;  
  5.     String rootPath = Environment.getExternalStorageDirectory().getPath();  
  6.     String currentPath = rootPath;  
  7.     List<Map<String, Object>> list = new ArrayList<>();  
  8.   
  9.     @Override  
  10.     public void onCreate(Bundle savedInstanceState) {  
  11.         super.onCreate(savedInstanceState);  
  12.         setContentView(R.layout.activity_file_explorer);  
  13.         listView = (ListView) findViewById(R.id.list_view);  
  14.         adapter = new SimpleAdapter(this, list, R.layout.list_item,  
  15.                 new String[]{"name", "img"}, new int[]{R.id.name, R.id.img});  
  16.         listView.setAdapter(adapter);  
  17.         listView.setOnItemClickListener(this);  
  18.         refreshListItems(currentPath);  
  19.     }  
  20.   
  21.     private void refreshListItems(String path) {  
  22.         setTitle(path);  
  23.         File[] files = new File(path).listFiles();  
  24.         list.clear();  
  25.         if (files != null) {  
  26.             for (File file : files) {  
  27.                 Map<String, Object> map = new HashMap<>();  
  28.                 if (file.isDirectory()) {  
  29.                     map.put("img", R.drawable.directory);  
  30.                 } else {  
  31.                     map.put("img", R.drawable.file_doc);  
  32.                 }  
  33.                 map.put("name", file.getName());  
  34.                 map.put("currentPath", file.getPath());  
  35.                 list.add(map);  
  36.             }  
  37.         }  
  38.         adapter.notifyDataSetChanged();  
  39.     }  
  40.   
  41.     @Override  
  42.     public void onItemClick(AdapterView<?> parent, View v, int position, long id) {  
  43.         currentPath = (String) list.get(position).get("currentPath");  
  44.         File file = new File(currentPath);  
  45.         if (file.isDirectory())  
  46.             refreshListItems(currentPath);  
  47.         else {  
  48.             Intent intent = new Intent();  
  49.             intent.putExtra("apk_path", file.getPath());  
  50.             setResult(RESULT_OK, intent);  
  51.             finish();  
  52.         }  
  53.   
  54.     }  
  55.   
  56.     @Override  
  57.     public void onBackPressed() {  
  58.         if (rootPath.equals(currentPath)) {  
  59.             super.onBackPressed();  
  60.         } else {  
  61.             File file = new File(currentPath);  
  62.             currentPath = file.getParentFile().getPath();  
  63.             refreshListItems(currentPath);  
  64.         }  
  65.     }  
  66. }  

這部分代碼由於和我們本篇文件的主旨沒什麼關係,主要是為了方便demo展示的,因此我就不進行講解了。

 

接下來修改MainActivity中的代碼,如下所示:

[java] view plain copy  
  1. /** 
  2.  * 仿360手機助手秒裝和智能安裝功能的主Activity。 
  3.  * 原文地址:http://blog.csdn.net/guolin_blog/article/details/47803149 
  4.  * @author guolin 
  5.  * @since 2015/12/7 
  6.  */  
  7. public class MainActivity extends AppCompatActivity {  
  8.   
  9.     TextView apkPathText;  
  10.   
  11.     String apkPath;  
  12.   
  13.     @Override  
  14.     protected void onCreate(Bundle savedInstanceState) {  
  15.         super.onCreate(savedInstanceState);  
  16.         setContentView(R.layout.activity_main);  
  17.         apkPathText = (TextView) findViewById(R.id.apkPathText);  
  18.     }  
  19.   
  20.     @Override  
  21.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  22.         if (requestCode == 0 && resultCode == RESULT_OK) {  
  23.             apkPath = data.getStringExtra("apk_path");  
  24.             apkPathText.setText(apkPath);  
  25.         }  
  26.     }  
  27.   
  28.     public void onChooseApkFile(View view) {  
  29.         Intent intent = new Intent(this, FileExplorerActivity.class);  
  30.         startActivityForResult(intent, 0);  
  31.     }  
  32.   
  33.     public void onSilentInstall(View view) {  
  34.         if (!isRoot()) {  
  35.             Toast.makeText(this, "沒有ROOT許可權,不能使用秒裝", Toast.LENGTH_SHORT).show();  
  36.             return;  
  37.         }  
  38.         if (TextUtils.isEmpty(apkPath)) {  
  39.             Toast.makeText(this, "請選擇安裝包!", Toast.LENGTH_SHORT).show();  
  40.             return;  
  41.         }  
  42.         final Button button = (Button) view;  
  43.         button.setText("安裝中");  
  44.         new Thread(new Runnable() {  
  45.             @Override  
  46.             public void run() {  
  47.                 SilentInstall installHelper = new SilentInstall();  
  48.                 final boolean result = installHelper.install(apkPath);  
  49.                 runOnUiThread(new Runnable() {  
  50.                     @Override  
  51.                     public void run() {  
  52.                         if (result) {  
  53.                             Toast.makeText(MainActivity.this, "安裝成功!", Toast.LENGTH_SHORT).show();  
  54.                         } else {  
  55.                             Toast.makeText(MainActivity.this, "安裝失敗!", Toast.LENGTH_SHORT).show();  
  56.                         }  
  57.                         button.setText("秒裝");  
  58.                     }  
  59.                 });  
  60.   
  61.             }  
  62.         }).start();  
  63.   
  64.     }  
  65.   
  66.     public void onForwardToAccessibility(View view) {  
  67.   
  68.     }  
  69.   
  70.     public void onSmartInstall(View view) {  
  71.   
  72.     }  
  73.   
  74.     /** 
  75.      * 判斷手機是否擁有Root許可權。 
  76.      * @return 有root許可權返回true,否則返回false。 
  77.      */  
  78.     public boolean isRoot() {  
  79.         boolean bool = false;  
  80.         try {  
  81.             bool = new File("/system/bin/su").exists() || new File("/system/xbin/su").exists();  
  82.         } catch (Exception e) {  
  83.             e.printStackTrace();  
  84.         }  
  85.         return bool;  
  86.     }  
  87.   
  88. }  

可以看到,在MainActivity中,我們對四個按鈕點擊事件的回調方法都進行了定義,當點擊選擇安裝包按鈕時就會調用onChooseApkFile()方法,當點擊秒裝按鈕時就會調用onSilentInstall()方法。在onChooseApkFile()方法方法中,我們通過Intent打開了FileExplorerActivity,然後在onActivityResult()方法當中讀取選擇的apk文件路徑。在onSilentInstall()方法當中,先判斷設備是否ROOT,如果沒有ROOT就直接return,然後判斷安裝包是否已選擇,如果沒有也直接return。接下來我們開啟了一個線程來調用SilentInstall.install()方法,因為安裝過程會比較耗時,如果不開線程的話主線程就會被卡住,不管安裝成功還是失敗,最後都會使用Toast來進行提示。

 

代碼就這麼多,最後我們來配置一下AndroidManifest.xml文件:

[html] view plain copy  
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.example.installtest">  
  4.   
  5.     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  
  6.   
  7.     <application  
  8.         android:allowBackup="true"  
  9.         android:icon="@mipmap/ic_launcher"  
  10.         android:label="@string/app_name"  
  11.         android:supportsRtl="true"  
  12.         android:theme="@style/AppTheme">  
  13.         <activity android:name=".MainActivity">  
  14.             <intent-filter>  
  15.                 <action android:name="android.intent.action.MAIN" />  
  16.   
  17.                 <category android:name="android.intent.category.LAUNCHER" />  
  18.             </intent-filter>  
  19.         </activity>  
  20.   
  21.         <activity android:name=".FileExplorerActivity"/>  
  22.     </application>  
  23.   
  24. </manifest>  

並沒有什麼特殊的地方,由於選擇apk文件需要讀取SD卡,因此在AndroidManifest.xml文件中要記得聲明讀SD卡許可權。

 

另外還有一點需要註意,在Android 6.0系統中,讀寫SD卡許可權被列為了危險許可權,因此如果將程式的targetSdkVersion指定成了23則需要做專門的6.0適配,這裡簡單起見,我把targetSdkVersion指定成了22,因為6.0的適配工作也不在文章的講解範圍之內。

現在運行程式,就可以來試一試秒裝功能了,切記手機一定要ROOT,效果如下圖所示:

可以看到,這裡我們選擇的網易新聞安裝包已成功安裝到手機上了,並且沒有彈出系統的安裝界面,由此證明秒裝功能已經成功實現了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 《 網頁設計大師2 》超越第一代版本,提供更新更精美的網頁素材模板。全部由國際頂級設計師精選打造,完全展示走在潮流 之前的設計風格。是網頁設計師/UI交互界面設計師必備工具。 《 網頁設計大師2 》內含近2000個全新南韓網站PSD模板,每個模板包含1-2個首頁,3-5個子頁面PSD設計源文件。另有 ...
  • html代碼 CSS代碼 效果圖: 、 下麵介紹三種圍住浮動元素的方法。最終達成的效果都是: 方法一:為父元素添加 overflow:hidden //overflow:hidden聲明的真正用途是 1.防止包含元素被超大內容撐大。應用overflow:hidden之後,包含元素依然保持其特定的寬度 ...
  • Object 類型 中大多數的引用類型都值都是 類型的實例, 也是使用最多的一個類型,主要用來在程式中 存儲和傳輸數據 創建Object實例的兩種方式 1. 使用 操作符後跟Object構造函數 var user = new Object(); user.name = "MIKE"; user.ag ...
  • 即將畢業的軟體工程大學生一枚,秋季招聘應聘的是Android,今年來到公司實習,要求做前端開發,所以一切只有現學,現在根據視頻來學習,然後開這個博客記錄一下自己的學習過程,廢話不多說,開寫。 4月6日學到的知識點: 一:<!DOCTYPE HTML> ! 聲明,註意的意思; doc document ...
  • 實現目標:年月日三個select 輸入框,以及一個hidden的input,通過js獲取input的值,如果有值切是日期格式,年月日select為input中的時間。否則為空。年預設區間段為1900年到當今年份 本人使用了bootstrap,class請參照bootstrap的相關說明 下麵是htm ...
  • 項目地址 https://github.com/brinley/jSignature demo地址 http://willowsystems.github.io/jSignature/ /demo/ 初始化 getData 獲得canvas上的圖像數據,推薦使用 base30格式,相對於其他格式,存 ...
  • 前言 為了更好理解浮動和position,建議先看看我寫的這篇文章《Html文檔流和文檔對象模型DOM理解》 正文 一、浮動 CSS設計float屬性的主要目的,是為了實現文本繞排圖片的效果。然而,這個屬性居然也成了創建多欄佈局最簡單的方式。 如何浮動一個元素?先設定其寬度width,再增加樣式規則 ...
  • 0.導入框架準備工作 •1. 將AFNetworking3.0+框架程式拖拽進項目 •2. 或使用Cocopod 導入AFNetworking3.0+ •3. 引入 #import "AFNetworking.h" > 1.UI準備工作 A. 定義一個全局的 NSURLSessionDownload ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...