6

We have a taxi app which has been quite successful in Europe. But recently one of our competitors has started checking if our app is installed and if it is, theirs won't run until the user uninstalls our app from their phone.

We initially did a few manual updates with a different package name to bypass their check but they are using a manual scan, i.e:

  1. They get a list of installed package names from user's phone
  2. List is sent to their servers
  3. Someone checks the names and flags our package name
  4. flags are pushed to their apps and once again we are blocked

They do not distribute their app via Play Store so we can't file a complaint about them to Google. Is there any other possibility to bypass this check? for example renaming the package name at runtime? We are losing users currently as the competitor has more orders (customers) for their drivers and most of our users would uninstall our app in order to use theirs.

UPDATE: Decided to decompile their app and see what they are doing there, I was wrong about their stategy, they have hardcoded our company and application name into their forbiddenApps preferences. Below is the code they are using, particularly the refineForbiddenSet() method is where our app gets flagged as far as I can see.

public class ForbiddenAppHelper
{

    public ForbiddenAppHelper()
    {
    }

    public static void UninstallApp(Context context, String s)
    {
        context.startActivity(new Intent("android.intent.action.DELETE", Uri.fromParts("package", s, null)));
    }

    public static boolean forbiddenAppsExist(Context context, String s)
    {
        return getForbidden(context, s).size() != 0;
    }

    public static Drawable getAppIcon(Context context, String s)
    {
        PackageManager packagemanager = context.getPackageManager();
        Drawable drawable;
        try
        {
            drawable = packagemanager.getApplicationIcon(s);
        }
        catch (android.content.pm.PackageManager.NameNotFoundException namenotfoundexception)
        {
            namenotfoundexception.printStackTrace();
            return null;
        }
        return drawable;
    }

    public static String getAppName(Context context, PackageManager packagemanager, String s)
    {
        if (packagemanager == null)
        {
            packagemanager = context.getPackageManager();
        }
        ApplicationInfo applicationinfo1 = packagemanager.getApplicationInfo(s, 0);
        ApplicationInfo applicationinfo = applicationinfo1;
_L1:
        android.content.pm.PackageManager.NameNotFoundException namenotfoundexception;
        Object obj;
        if (applicationinfo != null)
        {
            obj = packagemanager.getApplicationLabel(applicationinfo);
        } else
        {
            obj = "(unknown)";
        }
        return (String)obj;
        namenotfoundexception;
        applicationinfo = null;
          goto _L1
    }

    public static ArrayList getApplicationList(Context context)
    {
        ArrayList arraylist = new ArrayList();
        PackageManager packagemanager = context.getPackageManager();
        List list = packagemanager.getInstalledPackages(0);
        int i = 0;
        do
        {
            if (i >= list.size())
            {
                return arraylist;
            }
            PackageInfo packageinfo = (PackageInfo)list.get(i);
            if (packageinfo.versionName != null)
            {
                String s = packageinfo.packageName;
                arraylist.add(new InstalledApplication(packageinfo.applicationInfo.loadLabel(packagemanager).toString(), s));
            }
            i++;
        } while (true);
    }

    private static ArrayList getForbidden(Context context, String s)
    {
        HashSet hashset;
        StringTokenizer stringtokenizer;
        ArrayList arraylist;
        hashset = new HashSet();
        stringtokenizer = new StringTokenizer(s, ";");
        arraylist = new ArrayList();
        arraylist = getApplicationList(context);
_L3:
        boolean flag = stringtokenizer.hasMoreTokens();
        if (flag) goto _L2; else goto _L1
_L1:
        return refineFobiddenSet(arraylist, hashset);
_L2:
        hashset.add(stringtokenizer.nextToken());
          goto _L3
        Exception exception;
        exception;
        Crashlytics.logException(exception);
          goto _L1
    }

    public static String[] getForbiddenApps(Context context, String s)
    {
        ArrayList arraylist = getForbidden(context, s);
        return (String[])arraylist.toArray(new String[arraylist.size()]);
    }

    private static ArrayList refineFobiddenSet(ArrayList arraylist, HashSet hashset)
    {
        ArrayList arraylist1 = new ArrayList();
        Iterator iterator = hashset.iterator();
        do
        {
            if (!iterator.hasNext())
            {
                return new ArrayList(new HashSet(arraylist1));
            }
            String s = (String)iterator.next();
            Iterator iterator1 = arraylist.iterator();
            while (iterator1.hasNext()) 
            {
                InstalledApplication installedapplication = (InstalledApplication)iterator1.next();
                if (installedapplication.name.equals(s) || installedapplication.pname.equals(s))
                {
                    arraylist1.add(installedapplication.pname);
                }
            }
        } while (true);
    }
}
Nima
  • 161
  • 5
  • If they go after the app name, don't think that there is any easy method on changing you app name every time to fool their app. – woliveirajr Oct 22 '14 at 14:10
  • @woliveirajr me too, any other possibilities would be great. – Nima Oct 22 '14 at 14:13
  • 5
    Legal action would probably be better since the practice is anti-competitive, (don't take my word for it, there are no lawyers here), but to stop this your application would need super-user rights on any device it is installed on so it can hook the function and feed it lies. And most people don't have rooted devices. . . =( – Desthro Oct 22 '14 at 15:02
  • I think the only technical measure you can use here is to update your identifying information faster than they can check it. Untested, but you may be able to use Unicode characters to keep your name looking the same to users while making it look different in code. For example, various space characters, hyphens, combining symbols. – Zan Lynx Oct 22 '14 at 17:08

1 Answers1

13

I'd say that trying to defeat your competitors through technical means is a bad idea.

From your description, what your competitor is doing is basically saying to prospective customers: to use my service, you must agree not to use the service of my competitor. Send your lawyers; this is their stuff. It of course depends on the jurisdiction, but I bet that in most places in the World any half-competent lawyer should be able to sue them to death.

Tom Leek
  • 172,594
  • 29
  • 349
  • 481
  • 1
    We have an ongoing lawsuit, it's just a bit too slow. – Nima Oct 22 '14 at 15:12
  • 3
    Taking technical actions may give a legal argument to your competitors as part of that lawsuit (something like: "See ! They are doing it too !"). Hence my advice not to do it. – Tom Leek Oct 22 '14 at 15:46
  • 5
    You'd have to talk to your legal team, but you might be able to request an injunction against them using this practice, as it is actively causing you financial damage while the case is settled. – Doktor J Oct 22 '14 at 15:54