简体   繁体   中英

Removing Android debug resources in release

Currently I'm working on an app that retrieves json from a server. I'm testing the app on multiple devices, but I only have one SIM card. So in order to test on a device, I need to move the SIM card to that device. If the app can't contact the server via the APN, there won't be a result.

What I did is save an instance of said json in the resources and when in debug mode, use that as the result. This way I can test everything (but the connection/request) without having to switch the SIM card every time.

private class RequestTask extends AsyncTask< String, String, String > {
    ...
    @Override
    protected void onPostExecute( String pResult ) {
        ...
        if ( retrieveFromRawResource( pResult ) ) {
            pResult = CustomUtils.parseRawResource( getActivity().getResources(), R.raw.debugjson );
        }
        ...
    }

    private boolean retrieveFromRawResource( String pResult ) {
        return !isValidResult( pResult ) && CustomUtils.isDebugMode( getActivity() );
    }

    private boolean isValidResult( String pResult ) {
        return ( pResult != null && !pResult.isEmpty() );
    }
    ...
}

public class CustomUtils {
    ...
    public static String parseRawResource( Resources pResources, int pResourceId ) {
        StringBuilder builder = new StringBuilder();
        String line;
        try {
            InputStream is = pResources.openRawResource( pResourceId );
            BufferedReader reader = new BufferedReader( new InputStreamReader( is ) );
            while ( ( line = reader.readLine() ) != null )
            {
                builder.append( line );
                builder.append( "\n" );
            }
            return builder.toString();
        } catch ( Exception e ) {
            return null;
        }
    }
    ...
    public static boolean isDebugMode( Context pContext ) {
        return ( ( pContext.getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE ) != 0 );
    }
    ...
}

This works fine, the con to this though is the presence of the "unused" resource in the release APK. The file is quite big, so stripping it from all releases would be preferable.

Is something like this possible without having to remove/add it manually every time? Maybe using a combination of ant and Proguard? I could temporarily remove the raw json file before compiling and replace it afterwards, but the reference to that resource would still be in the code, even though it doesn't get called.

Okay, so here's what I ended up with. Since I'm already using ant, I decided to solve this in my custom_rules ant file. The trick is to override the release target, remove the debug resources, do the actual release and afterwards revert back. Since you can't completely remove the resources (they are still referenced in the code), I went with replacing them with dummy resources.

The properties file can be used to adjust the settings. In this case, all the files starting with 'debug_' in the 'res/' directory will be replaced with dummies and moved to the 'res-debug' directory.

debug.properties:

resource.files=**/debug_*
resource.dir=res/
tmp.dir=res-debug/

custom_rules.ant:

<project name="custom_rules">

    <target name="remove-debug-resources">
        <property file="debug.properties" prefix="debug" />

        <mkdir dir="${debug.tmp.dir}" />
        <!-- move all debug resources from the resources dir to the temporary debug dir -->
        <move todir="${debug.tmp.dir}" overwrite="false"> <!-- don't overwrite, in case last build failed -->
            <fileset dir="${debug.resource.dir}" casesensitive="yes" includes="${debug.resource.files}" />
        </move>
        <!-- create dummy resources for all the moved debug resources to satisfy the compiler -->
        <touch>
            <fileset dir="${debug.tmp.dir}" casesensitive="yes" includes="${debug.resource.files}" />
            <mapper type="glob" from="*" to="${debug.resource.dir}*" />
        </touch>
    </target>

    <target name="release" depends="remove-debug-resources, android_rules.release, restore-debug-resources" />

    <target name="restore-debug-resources">
        <property file="debug.properties" prefix="debug" />

        <!-- move all debug resources from the temporary debug dir back to the resources dir -->
        <move todir="${debug.resource.dir}" failonerror="false">
            <fileset dir="${debug.tmp.dir}" casesensitive="yes" includes="${debug.resource.files}" />
        </move>
        <delete dir="${debug.tmp.dir}" failonerror="false" />
    </target>

</project>

The most important thing to remember here is the fact that when compiling fails, the moved resources won't be restored. A simple 'ant restore-debug-resources' solves this, but you'd have to remember to do this manually. I couldn't find a clean-on-fail solution in ant.

Hope this helps others out as well!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM