प्रोग्रामेटिक रूप से एपीके इंस्टॉल / अनइंस्टॉल करें (पैकेजमैनेजर बनाम इंटेंट्स)


142

मेरा एप्लिकेशन अन्य एप्लिकेशन इंस्टॉल करता है, और उसे यह पता लगाने की आवश्यकता है कि उसने कौन से एप्लिकेशन इंस्टॉल किए हैं। बेशक, यह स्थापित अनुप्रयोगों की एक सूची को ध्यान में रखकर प्राप्त किया जा सकता है। लेकिन यह आवश्यक नहीं होना चाहिए! पैकेजबैनर की जिम्मेदारी होनी चाहिए कि वह स्थापित (ए, बी) संबंध बनाए रखे। वास्तव में, एपीआई के अनुसार यह है:

सार्वजनिक सार स्ट्रिंग getInstallerPackageName (स्ट्रिंग पैकेजनाम) - एक पैकेज स्थापित करने वाले एप्लिकेशन के पैकेज नाम को पुनः प्राप्त करें। यह पहचान करता है कि पैकेज किस बाजार से आया है।

वर्तमान दृष्टिकोण

Intent का उपयोग करके APK स्थापित करें

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
startActivity(intent);

APK का उपयोग करके अनइंस्टॉल करें:

Intent intent = new Intent(Intent.ACTION_DELETE, Uri.fromParts("package",
getPackageManager().getPackageArchiveInfo(apkUri.getPath(), 0).packageName,null));
startActivity(intent);

यह स्पष्ट रूप से वह तरीका नहीं है जैसे कि एंड्रॉइड मार्केट इंस्टॉल / अनइंस्टॉल करता है। वे PackageManager के समृद्ध संस्करण का उपयोग करते हैं। यह Android Git रिपॉजिटरी से एंड्रॉइड सोर्स कोड डाउनलोड करके देखा जा सकता है। नीचे दो छिपे हुए तरीके हैं जो इंटेंट दृष्टिकोण से मेल खाते हैं। दुर्भाग्य से वे बाहरी डेवलपर्स के लिए उपलब्ध नहीं हैं। लेकिन शायद वे भविष्य में होंगे?

बेहतर दृष्टिकोण

PackageManager का उपयोग करके APK स्थापित करना

/**
 * @hide
 * 
 * Install a package. Since this may take a little while, the result will
 * be posted back to the given observer.  An installation will fail if the calling context
 * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the
 * package named in the package file's manifest is already installed, or if there's no space
 * available on the device.
 *
 * @param packageURI The location of the package file to install.  This can be a 'file:' or a
 * 'content:' URI.
 * @param observer An observer callback to get notified when the package installation is
 * complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be
 * called when that happens.  observer may be null to indicate that no callback is desired.
 * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
 * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
 * @param installerPackageName Optional package name of the application that is performing the
 * installation. This identifies which market the package came from.
 */
public abstract void installPackage(
        Uri packageURI, IPackageInstallObserver observer, int flags,
        String installerPackageName);

PackageManager का उपयोग करके APK को अनइंस्टॉल करना

/**
 * Attempts to delete a package.  Since this may take a little while, the result will
 * be posted back to the given observer.  A deletion will fail if the calling context
 * lacks the {@link android.Manifest.permission#DELETE_PACKAGES} permission, if the
 * named package cannot be found, or if the named package is a "system package".
 * (TODO: include pointer to documentation on "system packages")
 *
 * @param packageName The name of the package to delete
 * @param observer An observer callback to get notified when the package deletion is
 * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
 * called when that happens.  observer may be null to indicate that no callback is desired.
 * @param flags - possible values: {@link #DONT_DELETE_DATA}
 *
 * @hide
 */
public abstract void deletePackage(
        String packageName, IPackageDeleteObserver observer, int flags);

मतभेद

  • इंटेंट्स का उपयोग करते समय स्थानीय पैकेज मैनेजर को यह जानकारी नहीं दी जाती है कि इंस्टालेशन किस एप्लीकेशन से हुआ है। विशेष रूप से, getInstallerPackageName (...) शून्य देता है।

  • छिपी विधि installPackage (...) एक पैरामीटर के रूप में इंस्टॉलर पैकेज नाम लेता है, और इस मूल्य को स्थापित करने में सबसे अधिक संभावना है।

सवाल

क्या इंटेंट्स का उपयोग करके पैकेज इंस्टॉलर नाम निर्दिष्ट करना संभव है? (शायद इंस्टॉलर पैकेज का नाम स्थापना के इरादे में एक अतिरिक्त के रूप में जोड़ा जा सकता है?)

युक्ति: यदि आप Android स्रोत कोड डाउनलोड करना चाहते हैं, तो आप यहाँ वर्णित चरणों का पालन कर सकते हैं: सोर्स ट्री डाउनलोड करना। * .Java फ़ाइलों को निकालने और उन्हें पैकेज पदानुक्रम के अनुसार फ़ोल्डरों में रखने के लिए आप इस नीट स्क्रिप्ट की जांच कर सकते हैं: ग्रहण में Android स्रोत कोड देखें


पाठ में कुछ यूआरआई गायब हैं। जैसे ही मुझे अनुमति दी जाएगी (नए उपयोगकर्ताओं को स्पैम को रोकने के लिए कुछ प्रतिबंध हैं) मैं उन्हें जोड़ दूंगा।
होवार्ड गेयथस

1
कार्यक्षमता की स्थापना रद्द कैसे करें?

2
@ user938893: "कैसे कार्यक्षमता की स्थापना रद्द करें?" - कुछ हार्ड-टू-अनइंस्टॉल मालवेयर पर काम कर रहे हैं, क्या हम?
डैनियल

जवाबों:


66

यह वर्तमान में तीसरे पक्ष के अनुप्रयोगों के लिए उपलब्ध नहीं है। ध्यान दें कि इंस्टॉलपैकेज () तक पहुंचने के लिए प्रतिबिंब या अन्य चाल का उपयोग करने से भी मदद नहीं मिलेगी, क्योंकि केवल सिस्टम एप्लिकेशन ही इसका उपयोग कर सकते हैं। (ऐसा इसलिए है क्योंकि यह उपयोगकर्ता द्वारा अनुमोदित किए जाने के बाद निम्न-स्तरीय इंस्टॉल तंत्र है, इसलिए नियमित अनुप्रयोगों के लिए उपयोग करना सुरक्षित नहीं है।)

इसके अलावा installPackage () फ़ंक्शन तर्क अक्सर प्लेटफ़ॉर्म रिलीज़ के बीच बदल गए हैं, इसलिए आप जो कुछ भी एक्सेस करने की कोशिश कर रहे हैं वह प्लेटफ़ॉर्म के विभिन्न संस्करणों पर विफल हो जाएगा।

संपादित करें:

यह भी इंगित करने योग्य है कि यह इंस्टॉलरपैकेज केवल प्लेटफ़ॉर्म में हाल ही में जोड़ा गया था (2.2?) और मूल रूप से इसका उपयोग ट्रैकिंग के लिए नहीं किया गया था जिसने ऐप इंस्टॉल किया है - इसका उपयोग प्लेटफ़ॉर्म द्वारा यह निर्धारित करने के लिए किया जाता है कि बग की रिपोर्ट करते समय किसे लॉन्च किया जाए। एप्लिकेशन, Android फ़ीडबैक लागू करने के लिए। (यह एपीआई विधि के तर्कों को बदलने के समय में से एक भी था।) इसे पेश किए जाने के बाद कम से कम एक लंबे समय के लिए, बाजार ने अभी भी इसका उपयोग उन ऐप्स को ट्रैक करने के लिए नहीं किया था (और यह बहुत अच्छी तरह से अभी भी इसका उपयोग नहीं कर सकता है। ), लेकिन इसके बजाय सिर्फ फीडबैक का ख्याल रखने के लिए "मालिक" के रूप में एंड्रॉइड फीडबैक ऐप (जो बाजार से अलग था) को सेट करने के लिए इसका इस्तेमाल किया।


"ध्यान दें कि इंस्टॉलपैकेज () तक पहुंचने के लिए प्रतिबिंब या अन्य चाल का उपयोग करने से भी मदद नहीं मिलेगी, क्योंकि केवल सिस्टम एप्लिकेशन ही इसका उपयोग कर सकते हैं।" मान लीजिए कि मैं किसी दिए गए प्लेटफ़ॉर्म के लिए मूल एंड्रॉइड के अलावा किसी अन्य के लिए ऐप इंस्टॉल / रिमूव / मैनेज कर रहा हूं। मुझे इंस्टॉल / हटाने तक कैसे पहुंचना चाहिए?
डैस्कैंडी

startActivity () एक उचित रूप से गठित इरादे के साथ। (मुझे यकीन है कि यह StackOverflow पर कहीं और उत्तर दिया गया है, इसलिए मैं यहां कुछ गलत होने के जोखिम पर सटीक उत्तर देने की कोशिश नहीं करूंगा।)
हैकबॉड

mmmkay, जो मानक एंड्रॉइड इंस्टॉल / डायलॉग को हटाता है। उन विवरणों को पहले ही संभाला जा चुका है - मैं "बस **** इस पैकेज को स्थापित कर रहा हूं" और "सिर्फ **** इस पैकेज को हटाएं" कार्यों की तलाश कर रहा है, शाब्दिक रूप से कोई प्रश्न नहीं पूछा गया है।
dascandy

2
जैसा कि मैंने कहा, ये थर्ड पार्टी एप्लिकेशन के लिए उपलब्ध नहीं हैं। यदि आप अपनी स्वयं की सिस्टम छवि बना रहे हैं, तो आपके पास प्लेटफ़ॉर्म कार्यान्वयन है, और आप वहां फ़ंक्शंस पा सकते हैं, लेकिन वे सामान्य थर्ड पार्टी ऐप्स के लिए उपलब्ध एपीआई का हिस्सा नहीं हैं।
हैकबॉड

मैं स्थापित, हटाने और बैकअप कार्यक्षमता के साथ एपीके फ़ाइल एक्सप्लोरर बना रहा हूं, तो क्या Google मुझे Google Play पर अपना एप्लिकेशन प्रकाशित करने की अनुमति देगा? और हम किस नीति को तोड़ने जा रहे हैं?
राहुल मंडालिया 13

86

Android P + को AndroidManifest.xml में इस अनुमति की आवश्यकता है

<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />

फिर:

Intent intent = new Intent(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:com.example.mypackage"));
startActivity(intent);

स्थापना रद्द करने के लिए। आसान लगता है ...


क्या यह कोड चलाने वाला ऐप हो सकता है? onDestroy()विधि में पसंद है ?
महदी-मालव

ACTION_INSTALL_PACKAGE के बारे में कैसे? क्या हम प्ले स्टोर से नवीनतम संस्करण हमारे ऐप को डाउनलोड और इंस्टॉल कर सकते हैं?
दास। जॉन

3
के बाद से एंड्रॉयड पी क्षुधा को हटाने प्रकट अनुमति "android.permission.REQUEST_DELETE_PACKAGES" कोई बात नहीं की आवश्यकता है यदि आप "ACTION_DELETE" या "ACTION_UNINSTALL_PACKAGE" का उपयोग developer.android.com/reference/android/content/...
Darklord5

Android P अनुमति का उल्लेख करने के लिए धन्यवाद, मैं फंस गया था और सुनिश्चित नहीं था कि पहले क्या चल रहा था।
अवी दर्शन

43

API स्तर 14 ने दो नए कार्य किए: ACTION_INSTALL_PACKAGE और ACTION_UNINSTALL_PACKAGE । वे क्रियाएं आपको EXTRA_RETURN_RESULT बूलियन अतिरिक्त उत्तीर्ण करने की अनुमति देती हैं ताकि एक (संयुक्त राष्ट्र) स्थापना परिणाम सूचना प्राप्त हो सके।

स्थापना रद्द संवाद लागू करने के लिए उदाहरण कोड:

String app_pkg_name = "com.example.app";
int UNINSTALL_REQUEST_CODE = 1;

Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);  
intent.setData(Uri.parse("package:" + app_pkg_name));  
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
startActivityForResult(intent, UNINSTALL_REQUEST_CODE);

और अपनी गतिविधि # onActivityResult विधि में अधिसूचना प्राप्त करें :

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == UNINSTALL_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {
            Log.d("TAG", "onActivityResult: user accepted the (un)install");
        } else if (resultCode == RESULT_CANCELED) {
            Log.d("TAG", "onActivityResult: user canceled the (un)install");
        } else if (resultCode == RESULT_FIRST_USER) {
            Log.d("TAG", "onActivityResult: failed to (un)install");
        }
    }
}

मैं इस एक्शन डायलॉग बॉक्स से कैसे पुष्टि कर सकता हूं कि या तो उपयोगकर्ता ने ठीक दबाया है या रद्द कर दिया है ताकि मैं इस पर आधारित निर्णय ले
सकूं

2
@Erum मैंने आपके लिए एक उदाहरण जोड़ा है
एलेक्स लिपोव

स्थापना पर, रद्द करें बटन पर परिणाम नहीं मिला onActivityResult पद्धति
diyoda_

2
एपीआई 25 से शुरू होने पर, कॉलिंग ACTION_INSTALL_PACKAGEको हस्ताक्षर स्तर की REQUEST_INSTALL_PACKAGESअनुमति की आवश्यकता होगी । इसी तरह, एपीआई 28 (एंड्रॉइड पी) से शुरू होने पर, कॉलिंग ACTION_UNINSTALL_PACKAGEको गैर-खतरनाक REQUEST_DELETE_PACKAGESअनुमति की आवश्यकता होगी । कम से कम डॉक्स के अनुसार।
स्टीव ब्लैकवेल

22

यदि आपके पास डिवाइस स्वामी (या प्रोफ़ाइल स्वामी, मैंने कोशिश नहीं की है) तो आप डिवाइस स्वामी API का उपयोग करके पैकेज को चुपचाप स्थापित / अनइंस्टॉल कर सकते हैं।

स्थापना रद्द करने के लिए:

public boolean uninstallPackage(Context context, String packageName) {
    ComponentName name = new ComponentName(MyAppName, MyDeviceAdminReceiver.class.getCanonicalName());
    PackageManager packageManger = context.getPackageManager();
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        PackageInstaller packageInstaller = packageManger.getPackageInstaller();
        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        params.setAppPackageName(packageName);
        int sessionId = 0;
        try {
            sessionId = packageInstaller.createSession(params);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        packageInstaller.uninstall(packageName, PendingIntent.getBroadcast(context, sessionId,
                new Intent("android.intent.action.MAIN"), 0).getIntentSender());
        return true;
    }
    System.err.println("old sdk");
    return false;
}

और पैकेज स्थापित करने के लिए:

public boolean installPackage(Context context,
                                     String packageName, String packagePath) {
    ComponentName name = new ComponentName(MyAppName, MyDeviceAdminReceiver.class.getCanonicalName());
    PackageManager packageManger = context.getPackageManager();
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        PackageInstaller packageInstaller = packageManger.getPackageInstaller();
        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        params.setAppPackageName(packageName);
        try {
            int sessionId = packageInstaller.createSession(params);
            PackageInstaller.Session session = packageInstaller.openSession(sessionId);
            OutputStream out = session.openWrite(packageName + ".apk", 0, -1);
            readTo(packagePath, out); //read the apk content and write it to out
            session.fsync(out);
            out.close();
            System.out.println("installing...");
            session.commit(PendingIntent.getBroadcast(context, sessionId,
                    new Intent("android.intent.action.MAIN"), 0).getIntentSender());
            System.out.println("install request sent");
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    System.err.println("old sdk");
    return false;
}

मुझे पता था कि मालिक होने के नाते ऐसा करना संभव है। जवाब के लिए धन्यवाद!
ल्यूक कॉउथेन

@sandeep यह सिर्फ आउटपुट स्ट्रीम में
एपीके

@LukeCauthen ने डिवाइस के मालिक होने के कारण आपकी कोशिश की है? क्या यह काम किया?
NetStarter

@NetStarter हां मेरे पास है। यह सिर्फ डिवाइस के मालिक होने के लिए ऐप में होने वाले गधे का दर्द है। एक बार जब आप ऐसा कर लेते हैं, तो आपको बहुत अधिक शक्ति मिलती है जो सामान्य रूप से रूट की आवश्यकता होती है।
ल्यूक काथेन

1
कृपया ध्यान दें कि काम करने के लिए अनइंस्टॉल करने के लिए अपने प्रकटीकरण के लिए आपको android.permission.DELETE_PACKAGES जोड़ना होगा (Api स्तर 22 या उससे कम पर परीक्षण किया गया)
बेंचूक

4

उन तरीकों तक पहुंचने का एकमात्र तरीका प्रतिबिंब के माध्यम से है। आप इन तरीकों PackageManagerसे कॉलिंग getApplicationContext().getPackageManager()और रिफ्लेक्शन एक्सेस का उपयोग करके किसी ऑब्जेक्ट पर हैंडल प्राप्त कर सकते हैं । इस ट्यूटोरियल की जाँच करें


यह 2.2 के साथ बहुत अच्छा काम करता है, लेकिन मुझे 2.3 के साथ इसका उपयोग करने का कोई सौभाग्य नहीं है
किसी ने 10

3
प्रतिबिंब सभी एपीआई संस्करणों में स्थिर नहीं है
हैंडलरएक्सप्लॉइट

3

Froyo स्रोत कोड के अनुसार, Intent.EXTRA_INSTALLER_PACKAGE_NAME अतिरिक्त कुंजी PackageInstallerActivity में इंस्टॉलर पैकेज नाम के लिए क्वेराइड किया गया है।


1
इस कमिट को देखकर मुझे लगता है कि यह काम करना चाहिए
सर्जियो91

2

एक निहित डिवाइस पर, आप उपयोग कर सकते हैं:

String pkg = context.getPackageName();
String shellCmd = "rm -r /data/app/" + pkg + "*.apk\n"
                + "rm -r /data/data/" + pkg + "\n"
                // TODO remove data on the sd card
                + "sync\n"
                + "reboot\n";
Util.sudo(shellCmd);

Util.sudo() यहाँ परिभाषित किया गया है।


क्या sdcard में पहले से डाउनलोड किया गया एप्लिकेशन इंस्टॉल करने का कोई तरीका है? या आप मुझे कुछ पेज पर यह जांचने के लिए सुझाव दे सकते हैं कि हम एंड्रॉइड प्लेटफॉर्म पर शेल पर किन कमांड का उपयोग कर सकते हैं?
यज्ञ

1
@yahya developer.android.com/tools/help/shell.html "pm android", शाम = पैकेज मैनेजर द्वारा पाया गया
18446744073709551615

1
@yahya चीटोग्राफी . com/ citguy / cheat - sheets/ android - package - manager - pm सेट-इंस्टाल-लोकेशन
18446744073709551615

आपका बहुत बहुत धन्यवाद! ये लिंक वाकई बहुत ही अच्छे मार्गदर्शक हैं :)
याहया

@ V.Kalyuzhnyu यह 2015 में वापस काम करता था। IIRC यह सैमसंग गैलेक्सी, शायद S5 था।
18446744073709551615

2

यदि आप अपने उपयोगकर्ता परिभाषित फ़ंक्शन के लिए पैरामीटर के रूप में पैकेज का नाम दे रहे हैं तो नीचे दिए गए कोड का उपयोग करें:

    Intent intent=new Intent(Intent.ACTION_DELETE);
    intent.setData(Uri.parse("package:"+packageName));
    startActivity(intent);

0

यदि आप कोटलिन, एपीआई 14+ का उपयोग कर रहे हैं, और केवल अपने ऐप के लिए अनइंस्टॉल संवाद दिखाना चाहते हैं:

startActivity(Intent(Intent.ACTION_UNINSTALL_PACKAGE).apply {
    data = Uri.parse("package:$packageName")
})

packageNameयदि आप उपयोगकर्ता को डिवाइस पर किसी अन्य एप्लिकेशन को अनइंस्टॉल करने के लिए संकेत देना चाहते हैं, तो आप किसी भी अन्य पैकेज के नाम को बदल सकते हैं


0

शर्त:

आपके एपीके को सिस्टम द्वारा हस्ताक्षरित करने की आवश्यकता है जैसा कि पहले बताया गया है। इसे प्राप्त करने का एक तरीका एओएसपी छवि का निर्माण करना और स्रोत कोड को निर्माण में जोड़ना है।

कोड:

सिस्टम ऐप के रूप में इंस्टॉल होने के बाद, आप एपीके को स्थापित करने और अनइंस्टॉल करने के लिए पैकेज मैनेजर के तरीकों का उपयोग कर सकते हैं:

इंस्टॉल:

public boolean install(final String apkPath, final Context context) {
    Log.d(TAG, "Installing apk at " + apkPath);
    try {
        final Uri apkUri = Uri.fromFile(new File(apkPath));
        final String installerPackageName = "MyInstaller";
        context.getPackageManager().installPackage(apkUri, installObserver, PackageManager.INSTALL_REPLACE_EXISTING, installerPackageName);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

स्थापना रद्द करें:

public boolean uninstall(final String packageName, final Context context) {
    Log.d(TAG, "Uninstalling package " + packageName);
    try {
        context.getPackageManager().deletePackage(packageName, deleteObserver, PackageManager.DELETE_ALL_USERS);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

आपके एपीके के इंस्टॉल / अनइंस्टॉल होने पर कॉलबैक करने के लिए आप इसका उपयोग कर सकते हैं:

/**
 * Callback after a package was installed be it success or failure.
 */
private class InstallObserver implements IPackageInstallObserver {

    @Override
    public void packageInstalled(String packageName, int returnCode) throws RemoteException {

        if (packageName != null) {
            Log.d(TAG, "Successfully installed package " + packageName);
            callback.onAppInstalled(true, packageName);
        } else {
            Log.e(TAG, "Failed to install package.");
            callback.onAppInstalled(false, null);
        }
    }

    @Override
    public IBinder asBinder() {
        return null;
    }
}

/**
 * Callback after a package was deleted be it success or failure.
 */
private class DeleteObserver implements IPackageDeleteObserver {

    @Override
    public void packageDeleted(String packageName, int returnCode) throws RemoteException {
        if (packageName != null) {
            Log.d(TAG, "Successfully uninstalled package " + packageName);
            callback.onAppUninstalled(true, packageName);
        } else {
            Log.e(TAG, "Failed to uninstall package.");
            callback.onAppUninstalled(false, null);
        }
    }

    @Override
    public IBinder asBinder() {
        return null;
    }
}

/**
 * Callback to give the flow back to the calling class.
 */
public interface InstallerCallback {
    void onAppInstalled(final boolean success, final String packageName);
    void onAppUninstalled(final boolean success, final String packageName);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.