android 实现静默安装、卸载

android中应用的安装卸载,大家(用android设备的)肯定不陌生。这里就来浅谈android应用的安装、卸载的实现方式。

1.系统安装程序

android自带了一个安装程序---/system/app/PackageInstaller.apk.大多数情况下,我们手机上安装应用都是通过这个apk来安装的。代码使用也非常简单:


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 安装apk */
    public static void installApk(Context context, String fileName) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.parse("file://" + fileName),
                "application/vnd.android.package-archive");
        context.startActivity(intent);
    }
 
    /* 卸载apk */
    public static void uninstallApk(Context context, String packageName) {
        Uri uri = Uri.parse("package:" + packageName);
        Intent intent = new Intent(Intent.ACTION_DELETE, uri);
        context.startActivity(intent);
    }


通过发一个Intent,把应用所在的路径封装整uri.之后默认启动了PackageInstaller.apk来安装程序了。
但是此种情况下,仅仅是个demo而已,很难达到开发者的需求。如:
 

  • 界面不好

  • 什么时候安装完了,卸载完了呢?

为了达到自己的需求,相信很多人都会接着来监听系统安装卸载的广播,继续接下来的代码逻辑。


2.监听系统发出的安装广播

在安装和卸载完后,android系统会发一个广播

  • android.intent.action.PACKAGE_ADDED(安装)

  • android.intent.action.PACKAGE_REMOVED(卸载)


咱们就监听这广播,来做响应的逻辑处理。实现代码:


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MonitorSysReceiver extends BroadcastReceiver{
       
    @Override  
    public void onReceive(Context context, Intent intent){
        //接收安装广播 
        if (intent.getAction().equals("android.intent.action.PACKAGE_ADDED")) {   
            //TODO    
        }   
        //接收卸载广播  
        if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) {   
            //TODO
        }
    }
}

AndroidMenifast.xml里配置:



?
1
2
3
4
5
6
  <receiver android:name=".MonitorSysReceiver">   
            <intent-filter>  
             <action android:name="android.intent.action.PACKAGE_ADDED" />  
             <action android:name="android.intent.action.PACKAGE_REMOVED" />  
            </intent-filter>  
  </receiver>


到此,确实安装卸载的整体流程都知道了,但是这个效果肯定是无法达到项目的需求。
一般这种应用商店类的项目,肯定是会要自定义提示框效果的安装卸载功能,而不是调用系统的安装程序。
那咱就要想法子实现静默安装、卸载咯。
网上有很多法子,如执行adb install 或pm install -r命令安装。但我想这并不可靠。记得之前有做过一个应用来执行linux命令,是通过RunTime来执行命令的。
后来发现其实并不靠谱,还不如直接用C代码来实现。
下面这种调用系统隐藏api接口来实现静默安装卸载,是比较大众靠谱的,实现自定义的提示界面。O(∩_∩)O~


3.系统隐藏的api

隐藏api,顾名思义,普通情况下肯定是调用不到的。翻翻源码\frameworks\base\core\java\android\content\pm目录下PackageManager.java,应该发现
在注释行里有加上@hide声明。调用的安装下载接口如下:


?
1
2
3
public abstract void installPackage(Uri packageURI,
            IPackageInstallObserver observer, int flags,
            String installerPackageName);
?
1
2
 public abstract void deletePackage(String packageName,
 IPackageDeleteObserver observer, int flags);

并且都是抽象方法,需要咱们实现。 

看参数里IPackageInstallObserver  observer一个aidl回调通知接口,当前目录中找到这接口:

?
1
2
3
4
5
6
7
8
9
package android.content.pm;
 
/**
 * API for installation callbacks from the Package Manager.
 *   @hide
 */
oneway interface IPackageInstallObserver {
    void packageInstalled(in String packageName, int returnCode);
}

好吧,这里有现成的干货,咱拿过来直接用呗(当然如果没有源码的那就算了,那能实现的只是demo)。具体步骤:


  • 从源码中拷贝要使用的aidl回调接口:IPackageInstallObserver.aidl、IPackageDeleteObserver.aidl当然完全可以拷贝整个pm目录,这样就不会报错了O(∩_∩)O~。

  • 作者项目里面用到了pm,所以把PackageManager.java以及涉及到的一些文件也拷贝过来了,不然eclipse报找不到PackageManager对象。结构如下:

    (注:此处的包名android.content.pm一定要和源码目录结构一致,不然源码里编译会提示找不到aidl接口。一切朝源码编译看齐)
    此处有2种方式实现:
    1.直接只取IPackageDeleteObserver.aidl和IPackagerInstallObserver.aidl、IPackageMoveObserver.aidl等要使用的接口,然后通过bindService来和系统连接服务,然后直接调用接口即可(这种没有方式作者没试过,不过原理上来说应该是可行的,除非系统没有这个Service实现这个接口。有需求的可以深究下)
    2.作者此处的方法是直接拷贝了源码PackageManager.java等文件过来,不过靠过来之后eclipse会提示一些接口错误,但这里作者把上面那几个.java文件都放空了,因为用不到,只是为了编译过才拷贝了那么多文件。最简单的就是直接拷贝4个文件即可:
    PackageManager.java
    IPackageDeleteObserver.aidl

    IPackagerInstallObserver.aidl
    IPackageMoveObserver.aidl
    然后把PackageManager.java中报的异常的接口都注释掉即可


  • 实现回调接口,代码如下

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class MyPakcageInstallObserver extends IPackageInstallObserver.Stub {
            Context cxt;
            String appName;
            String filename;
            String pkname;
     
            public MyPakcageInstallObserver(Context c, String appName,
                     String filename,String packagename) {
                this.cxt = c;
                this.appName = appName;
                this.filename = filename;
                this.pkname = packagename;
            }
     
            @Override
            public void packageInstalled(String packageName, int returnCode) {
                Log.i(TAG, "returnCode = " + returnCode);// 返回1代表安装成功
                            if (returnCode == 1) {
                                //TODO
                            }
                Intent it = new Intent();
                it.setAction(CustomAction.INSTALL_ACTION);
                it.putExtra("install_returnCode", returnCode);
                it.putExtra("install_packageName", packageName);
                it.putExtra("install_appName", appName); cxt.sendBroadcast(it);
            }
        }

    卸载回调接口同上。

  • 调用PackageManager.java隐藏方法,代码如下:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /**
         * 静默安装
         * */
        public static void autoInstallApk(Context context, String fileName,
                String packageName, String APPName) {
            Log.d(TAG, "jing mo an zhuang:" + packageName + ",fileName:" + fileName);
            File file = new File(fileName);
            int installFlags = 0;
            if (!file.exists())
                return;
            installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
            if (hasSdcard()) {
                installFlags |= PackageManager.INSTALL_EXTERNAL;
            }
            PackageManager pm = context.getPackageManager();
            try {
                IPackageInstallObserver observer = new MyPakcageInstallObserver(
                        context, APPName, appId, fileName,packageName,type_name);
                Log.i(TAG, "########installFlags:" + installFlags+"packagename:"+packageName);
                pm.installPackage(Uri.fromFile(file), observer, installFlags,
                        packageName);
            } catch (Exception e) {
                 
            }
     
        }

    卸载调用同上

很多码友联系,这里经常出错,现整理参考代码如下(下面代码有些格式问题)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
package cn.thear;
 
import java.io.File;
 
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.os.RemoteException;
import android.util.Log;
 
public class ApkOperateManager {
    public static String TAG = "ApkOperateManager";
 
    /***安装apk */
    public static void installApk(Context context, String fileName) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.parse("file://" + fileName),
                "application/vnd.android.package-archive");
        context.startActivity(intent);
    }
 
    /**卸载apk */
    public static void uninstallApk(Context context, String packageName) {
        Uri uri = Uri.parse("package:" + packageName);
        Intent intent = new Intent(Intent.ACTION_DELETE, uri);
        context.startActivity(intent);
    }
 
    /**
     * 静默安装
     * */
    public static void installApkDefaul(Context context, String fileName,
            String packageName, String APPName, String appId, String type_name) {
        Log.d(TAG, "jing mo an zhuang:" + packageName + ",fileName:" + fileName
                + ",type_name:" + type_name);
        File file = new File(fileName);
        int installFlags = 0;
        if (!file.exists())
            return;
        installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
        if (hasSdcard()) {
            installFlags |= PackageManager.INSTALL_EXTERNAL;
        }
        PackageManager pm = context.getPackageManager();
        // try {  try {
            IPackageInstallObserver observer = new MyPakcageInstallObserver(
                    context, APPName, appId, fileName, packageName, type_name);
            Log.i(TAG, "########installFlags:" + installFlags + "packagename:"
                    + packageName);
            pm.installPackage(Uri.fromFile(file), observer, installFlags,
                    packageName);
        } catch (Exception e) {
            ((MarketApplication) context).setApp_detail_status(appId,
                    MarketApplication.APP_STATUS_NOTEXIT);
        }
 
    }
 
    /* 静默卸载 */
    public static void uninstallApkDefaul(Context context, String action,
            String packageName) {
        PackageManager pm = context.getPackageManager();
        IPackageDeleteObserver observer = new MyPackageDeleteObserver(context,
                action, packageName);
        pm.deletePackage(packageName, observer, 0);
    }
 
    /* 静默卸载回调 */
             private static class MyPackageDeleteObserver extends
            IPackageDeleteObserver.Stub {
        Context cxt;
        String action;
        String pkname;
 
        public MyPackageDeleteObserver(Context c, String action, String pkname) {
            this.cxt = c;
            this.action = action;
            this.pkname = pkname;
        }
 
        @Override
public void packageDeleted(String packageName, int returnCode) {
            Log.d(TAG, "returnCode = " + returnCode + ",action:" + action
                    + "packageName:" + packageName + ",pkname:" + pkname);// 返回1代表卸载成功
            if (returnCode == 1) {//TODO 以下是删除数据库记录,只做参考
                /*SharedPreferences installedAPPInfo = cxt.getSharedPreferences(
                        "installedAPPInfo", Context.MODE_WORLD_READABLE);
                if (installedAPPInfo.contains(packageName)) {
                    String appId = installedAPPInfo.getString(packageName,
                            "no this appId");
                    ((MarketApplication) cxt.getApplicationContext())
                            .setApp_detail_status(appId,
                                    MarketApplication.APP_STATUS_NOTEXIT);
                    installedAPPInfo.edit().remove(packageName).commit();
                    ContentResolver conResolver = cxt.getContentResolver();
                    conResolver.delete(InstalledAppInfo.CONTENT_URI,
                            InstalledAppInfo.APP_PKNAME + " = " + "'" + pkname
                                    + "'", null);
                }
                MarketApplication ma = ((MarketApplication) cxt
                        .getApplicationContext());
                Log.e(TAG, "###packageDeleted###111size:"
                        + ma.getManagerLists().size());
                ma.removeManagerItem(pkname);
                ma.removeUpdateItem(pkname);
                Log.e(TAG, "##packageDeleted####22222size:"
                        + ma.getManagerLists().size());*/
            }
             
             
            Intent it = new Intent();
            it.setAction(action);
            it.putExtra("uninstall_returnCode", returnCode);
            cxt.sendBroadcast(it);
        }
    }
 
    /* 静默安装回调 */
    private static class MyPakcageInstallObserver extends
            IPackageInstallObserver.Stub {
        Context cxt;
        String appName;
        String appId;
        String filename;
        String pkname;
        String type_name;
 
        public MyPakcageInstallObserver(Context c, String appName,
                String appId, String filename, String packagename,
                String type_name) {
            this.cxt = c;
            this.appName = appName;
            this.appId = appId;
            this.filename = filename;
            this.pkname = packagename;
            this.type_name = type_name;
        }
 
        @Override
        public void packageInstalled(String packageName, int returnCode) {
            MarketApplication ma = ((MarketApplication) cxt
                    .getApplicationContext());
            Log.i(TAG,
                    "returnCode = " + returnCode + ","
                            + ma.getApp_detail_status(appId));// 返回1代表安装成功
            Intent it = new Intent();
            it.setAction(CustomAction.INSTALL_ACTION);
            it.putExtra("install_returnCode", returnCode);
            it.putExtra("install_packageName", packageName);
            it.putExtra("install_appName", appName);
            it.putExtra("install_appId", appId);
            if (returnCode == 1) {
                //ma.getAPPList();
                //ma.setManagerLists();
                if (ma.getApp_detail_status(appId) == MarketApplication.APP_STATUS_UPDATITNG) {
                    ma.removeUpdateItem(pkname);
                    cxt.sendBroadcast(it);
                    return;
                }
 
                SharedPreferences installedAPPInfo = cxt.getSharedPreferences(
                        "installedAPPInfo", Context.MODE_WORLD_READABLE);
                installedAPPInfo.edit().putString(packageName, appId).commit();
 
                // 保存信息到数据库
                if (appId != null && appName != null && pkname != null
                        && type_name != null) {
                    ContentResolver conResolver = cxt.getContentResolver();
                    ContentValues values = new ContentValues();
                    values.put(InstalledAppInfo.APP_ID, appId);
                    values.put(InstalledAppInfo.APP_NAME, appName);
                    values.put(InstalledAppInfo.APP_PKNAME, pkname);
                    values.put(InstalledAppInfo.APP_TYPENAME, type_name);
                    Uri result = conResolver.insert(
                            InstalledAppInfo.CONTENT_URI, values);
                    Log.i(TAG,
                            "#########install suscess...result:"
                                    + result.toString());
                }
                ma.setApp_detail_status(appId,
                        MarketApplication.APP_STATUS_INSTALLED);
            } 
            File f = new File(filename);
            if (f.exists()) {
                f.delete();
            }
 
            cxt.sendBroadcast(it);
        }
    }
 
    /**
     * sd卡不存在
     */
    public static final int NO_SDCARD = -1;
 
    /**
     * 移动应用到SD Card
     * 
     * @param context
     * @param pkname
     * @return
     */
    public static void movePackage(Context context, String pkname) {
        PackageManager pm = context.getPackageManager();
        MovePackageObserver mpo = new MovePackageObserver();
        pm.movePackage(pkname, mpo, PackageManager.INSTALL_EXTERNAL);
    }
 
    /**
     * 移动应用的回调
     */
    public static class MovePackageObserver extends IPackageMoveObserver.Stub {
 
        public MovePackageObserver() {
        }
 
        @Override
        public void packageMoved(String packageName, int returnCode)
                throws RemoteException {
            Log.i(TAG, "packagename:" + packageName + ",returnCode:"
                    + returnCode);
        }
    }
 
    /**
     * 判断有无sd卡
     * */
    public static boolean hasSdcard() {
        String status = Environment.getExternalStorageState();
        if (status.equals(Environment.MEDIA_MOUNTED)
                || status.equals("/mnt/sdcard")) {
            Log.i(TAG, "has sdcard....");
            return true;
        } else {
            return false;
        }
    }
}





 自此,静默安装卸载代码实现。最后在AndroidMenifast.xml中要注册权限和添加为系统用户组,如果eclipse编译的话,并记得签名(不会的话戳这里)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="xxx.xxx.xxxx"   
    android:installLocation="internalOnly"
    android:versionCode="1"
    android:versionName="1.0.19"
    android:sharedUserId="android.uid.system"
     >
     
    <uses-sdk android:minSdkVersion="4"/>
  
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> 
    ...
 
</manifest>

注:最后特别注意一点,因为下载的apk等只有rw----- root可读写权限,必须用个办法来给下载的apk赋权限,让系统级应用可以打开操作。这里作者是通过一个jni来调用C层接口,实现给指定的apk赋权限。然后执行安装apk过程

permission_change.cpp


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <jni.h>
#include <string.h>
 
#include <android/log.h>
#include <sys/types.h> 
#include <sys/stat.h>
#include <stdio.h>
 
 
#define LOGI printf
#define LOGE printf
 
    static const char *classPathName = "com/utils/PermissionNative"; //此处包名视java层native包名而定
    typedef union{
        JNIEnv* env;
        void* venv;
     }UnionJNIEnvToVoid;
     static jboolean ChangePermission(const char* str)
     {    
           const char* p;
           char tmp_path[50];
           memset(tmp_path,0,sizeof(tmp_path));
           p = str+5;
          while(p < str+strlen(str))
          {
              if(*p =='/')
              { 
                  memcpy(tmp_path,str,p-str);
                  if(chmod(tmp_path,0755) == -1)
                  {
                      LOGI("chmod  %s failed!\n",tmp_path);        
                    return JNI_FALSE;//    
                  }
                  LOGI("tmp_path_chmod = %s\n",tmp_path);        
              }
              p++;
          }
          if(chmod(str,0755) == -1)
              {  
                    LOGI("chmod  %s failed!\n",str);                     
                   return JNI_FALSE;//    
              }
          return JNI_TRUE;//
     } 
 
     static jboolean   PermissionChange(JNIEnv *env, jobject thiz,jstring path)
     {
          const char* str;
          str = env->GetStringUTFChars(path,false);
          if(str == NULL)
          {
                return JNI_FALSE;
          }
          if(ChangePermission(str))
          {
            env->ReleaseStringUTFChars(path,str);
            return JNI_TRUE;//JNI_FALSE
          } else {
                env->ReleaseStringUTFChars(path,str);
              return JNI_FALSE;//
          }
     }
    
    static JNINativeMethod methods[] = {
      {"native_permission_change", "(Ljava/lang/String;)Z", (void*)PermissionChange },
    };
 
    /*
     * Register several native methods for one class.
     */
    static int registerNativeMethods(JNIEnv* env, const char* className,
        JNINativeMethod* gMethods, int numMethods)
    {
        jclass clazz;
        clazz = env->FindClass(className);
        if (clazz == NULL) {
            LOGI("Native registration unable to find class '%s'\n", className);
            return JNI_FALSE;
        }
        LOGI("FindClass succ\n");
        if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
            LOGI("RegisterNatives failed for '%s'\n", className);
            return JNI_FALSE;
        }
        LOGI("RegisterNatives succ\n");
        return JNI_TRUE;
    }
 
    /*
     * Register native methods for all classes we know about.
     *
     * returns JNI_TRUE on success.
     */
    static int registerNatives(JNIEnv* env)
    {
      if (!registerNativeMethods(env,classPathName,
                    methods, sizeof(methods) / sizeof(methods[0]))) {
          return JNI_FALSE;
      }
      LOGI("registerNatives succ\n");
      return JNI_TRUE;
    }
 
    // -------------------------------------------------------------------------
 
    /*
     * This is called by the VM when the shared library is first loaded.
     */
 
 
 
    jint JNI_OnLoad(JavaVM* vm, void* reserved)
    {
        UnionJNIEnvToVoid uenv;
        uenv.venv = NULL;
        jint result = -1;
        JNIEnv* env = NULL;
 
        LOGI("JNI_OnLoad begin\n");
 
        if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
            LOGI("ERROR: GetEnv failed\n");
            goto bail;
        }
        LOGI("GetEnv succ\n");
        env = uenv.env;
 
        if (registerNatives(env) != JNI_TRUE) {
            LOGI("ERROR: registerNatives failed\n");
            goto bail;
        }
        LOGI("registerNatives succ!");
        result = JNI_VERSION_1_4;
 
    bail:
        return result;
    }

Android.mk如下: 

?
1
2
3
4
5
6
7
8
9
LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE :=false
LOCAL_MODULE_TAGS := eng
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
LOCAL_SRC_FILES :=permission_change.cpp
LOCAL_MODULE :=libpermission_change_jni
 
include $(BUILD_SHARED_LIBRARY)


4.拷贝apk

条件:

  1. 获取系统权限

  2. 拷贝apk到data/app

注:4.2和4.0上以测试通过,不过没有回调提示的,需要自己代码实现


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Inno Setup是一款流行的Windows安装程序创建工具,支持静默安装静默安装指的是在用户操作的情况下,自动进行软件安装而无需用户进行任何操作。以下是如何使用Inno Setup进行静默安装的方法: 静默安装: 1.首先,确保已经准备好要安装的软件的所有必要文件和文件夹。 2.创建一个包含安装程序信息的脚本文件,可以使用Inno Setup提供的脚本编辑器或其他文本编辑器来编写。 3.在脚本文件中,使用[Setup]部分的相应选项配置静默安装模式。例如,可以将"DisableStartupPrompt"选项设置为yes,这将禁用任何与用户操作相关的提示消息。 4.保存和编译脚本,生成安装程序。 5.在命令行中执行安装程序,并使用"/VERYSILENT"和"/NORESTART"参数以及其他可能的参数来启用静默安装模式。例如,"setup.exe /VERYSILENT /NORESTART"。 6.安装程序将在后台运行,进行静默安装: 1.确定要的软件的安装位置和程序的名称。 2.打开命令提示符或PowerShell窗口,并导航到安装目录。 3.在命令行中输入程序的名称,通常为"unins000.exe"或类似名称。 4.使用"/VERYSILENT"参数来启用静默模式。例如,"unins000.exe /VERYSILENT"。 5.程序将在后台运行,进行静默。 6.完成后,软件将从系统中完全移除。 总结而言,Inno Setup可以通过配置脚本文件和使用适当的参数,在静默模式下进行软件的安装。这对于需要批量安装或远程安装的情况下非常有用,同时也减少了用户操作的繁琐。 ### 回答2: Inno Setup 是一个常用的安装程序制作工具,可以帮助开发者创建 Windows 平台下的安装程序。而静默安装则是 Inno Setup 提供的两个重要功能。 静默安装(Silent Installation)是指在用户无需进行任何交互的情况下进行安装。通过传递命令行参数给 Inno Setup 执行文件,可以实现静默安装。一般来说,只需要在执行文件后面添加 /SILENT 或 /VERYSILENT 参数就可以实现静默安装。/SILENT 参数会显示进度条,/VERYSILENT 参数则完全不显示任何界面。 静默(Silent Uninstallation)是指对已经安装的软件进行无需用户交互的。同样地,可以通过添加命令行参数给 Inno Setup 文件实现静默。一般来说,在文件后面添加 /SILENT 或 /VERYSILENT 参数即可实现静默。 通过使用 Inno Setup 的静默安装功能,可以实现自动化的软件发布和管理。开发者可以在无需用户干预的情况下,批量安装软件,提高效率并减少错误。这对于企业环境中的大规模软件部署和维护尤为重要。 总而言之,Inno Setup 提供了静默安装的功能,使得软件部署和维护更加便捷高效。通过合理运用这两个功能,开发者可以轻松实现自动化的软件安装,提高工作效率。 ### 回答3: Inno Setup 是一款功能强大的安装程序制作工具,也可以通过静默安装的方式来安装软件。 静默安装是一种在用户无感知的情况下自动完成安装过程的方式。在使用 Inno Setup 进行静默安装时,我们可以通过命令行参数来实现。具体步骤如下: 1. 打开命令提示符或者脚本编辑器。 2. 切换到 Inno Setup 的安装程序所在的目录。 3. 输入以下命令进行静默安装: ``` Setup.exe /SILENT /NORESTART ``` `/SILENT` 参数表示以静默模式运行安装程序,安装过程中不会显示任何界面和提示信息。 `/NORESTART` 参数表示安装完成后不自动重启计算机。 4. 等待一段时间,直到安装程序自动完成安装。 同样地,我们也可以使用相同的方式进行静默。 1. 打开命令提示符或者脚本编辑器。 2. 切换到 Inno Setup 的安装程序所在的目录。 3. 输入以下命令进行静默: ``` Setup.exe /SILENT /UNINSTALL ``` `/SILENT` 参数表示以静默模式运行程序,过程中不会显示任何界面和提示信息。 `/UNINSTALL` 参数表示执行操作。 4. 等待一段时间,直到程序自动完成。 通过以上步骤,我们可以实现使用 Inno Setup 进行静默安装的功能。这种方式可以有效减少用户的操作,提高安装的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值