luncrzs 发布的文章

Handle uncaught exception in Android app

  1. Handle uncaughtException in your Application subclass.
  2. After catching an exception, start a new activity to ask the user to send a log.
  3. Extract the log info from logcat's files and write to your own file.
  4. Start an email app, providing your file as an attachment.
  5. Manifest: filter your activity to be recognized by your exception handler.
  6. Optionally, setup Proguard to strip out Log.d() and Log.v().
public class MyApplication extends Application
{
  public void onCreate ()
  {
    // Setup handler for uncaught exceptions.
    Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
    {
      @Override
      public void uncaughtException (Thread thread, Throwable e)
      {
        handleUncaughtException (thread, e);
      }
    });
  }

  public void handleUncaughtException (Thread thread, Throwable e)
  {
    e.printStackTrace(); // not all Android versions will print the stack trace automatically

    Intent intent = new Intent ();
    intent.setAction ("com.mydomain.SEND_LOG"); // see step 5.
    intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); // required when starting from Application
    startActivity (intent);

    System.exit(1); // kill off the crashed app
  }
}
private String extractLogToFile()
{
  PackageManager manager = this.getPackageManager();
  PackageInfo info = null;
  try {
    info = manager.getPackageInfo (this.getPackageName(), 0);
  } catch (NameNotFoundException e2) {
  }
  String model = Build.MODEL;
  if (!model.startsWith(Build.MANUFACTURER))
    model = Build.MANUFACTURER + " " + model;

  // Make file name - file must be saved to external storage or it wont be readable by
  // the email app.
  String path = Environment.getExternalStorageDirectory() + "/" + "MyApp/";
  String fullName = path + <some name>;

  // Extract to file.
  File file = new File (fullName);
  InputStreamReader reader = null;
  FileWriter writer = null;
  try
  {
    // For Android 4.0 and earlier, you will get all app's log output, so filter it to
    // mostly limit it to your app's output.  In later versions, the filtering isn't needed.
    String cmd = (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) ?
                  "logcat -d -v time MyApp:v dalvikvm:v System.err:v *:s" :
                  "logcat -d -v time";

    // get input stream
    Process process = Runtime.getRuntime().exec(cmd);
    reader = new InputStreamReader (process.getInputStream());

    // write output stream
    writer = new FileWriter (file);
    writer.write ("Android version: " +  Build.VERSION.SDK_INT + "\n");
    writer.write ("Device: " + model + "\n");
    writer.write ("App version: " + (info == null ? "(null)" : info.versionCode) + "\n");

    char[] buffer = new char[10000];
    do 
    {
      int n = reader.read (buffer, 0, buffer.length);
      if (n == -1)
        break;
      writer.write (buffer, 0, n);
    } while (true);

    reader.close();
    writer.close();
  }
  catch (IOException e)
  {
    if (writer != null)
      try {
        writer.close();
      } catch (IOException e1) {
      }
    if (reader != null)
      try {
        reader.close();
      } catch (IOException e1) {
      }

    // You might want to write a failure message to the log here.
    return null;
  }

  return fullName;
}
public class SendLog extends Activity implements OnClickListener
{
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    requestWindowFeature (Window.FEATURE_NO_TITLE); // make a dialog without a titlebar
    setFinishOnTouchOutside (false); // prevent users from dismissing the dialog by tapping outside
    setContentView (R.layout.send_log);
  }
}
<activity
    android:name="com.mydomain.SendLog"
    android:theme="@android:style/Theme.Dialog"
    android:textAppearance="@android:style/TextAppearance.Large"
    android:windowSoftInputMode="stateHidden">
    <intent-filter>
      <action android:name="com.mydomain.SEND_LOG" />
      <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
-assumenosideeffects class android.util.Log {
    public static int v(...);
    public static int d(...);
}

Debug Release采用不同资源

From Steffen Funke

Just to give a working example to my comment above:

declare a resValue in your defaultConfig which will become the Application's name. (Attention: if you choose to name it app_name, be sure to delete the original app_name property from your strings.xml file, or it will clash.)

defaultConfig {
    // applicationId, versionCode, etc.

    (...)

    // define your base Applications name here
    resValue 'string', 'app_name', 'MyApp'
}

set your productFlavors as you did already. You can leave them empty if it is ok for you to concat your App's name with the flavor's name only, or provide an explicit resValue, which will override the value from defaultConfig.

productFlavors {
    dev {
        // resValue 'string', 'app_name', 'MyAppDevFlavor'
    }

    prod {
        // resValue 'string', 'app_name', 'MyAppProdFlavor'
    }
}

configure the resValue's name at gradle configuration time

android.applicationVariants.all { variant ->
    // get app_name field from defaultConfig
    def appName = variant.mergedFlavor.resValues.get('app_name').getValue()

    // concat new App name with each flavor's name
    appName = "${appName}"
    variant.productFlavors.each { flavor ->
        appName += " ${flavor.name}"
    }

    // optionally add buildType name
    appName += " ${variant.buildType.name}"

    // your requirement: if buildType == debug, add DEV to App name
    if(variant.buildType.name == "debug") {
        appName += " DEV"
    }

    // set new resVale
    variant.resValue 'string', 'app_name', appName
}

In your AndroidManifest, set the app_name field:

    <application
    ...
    android:label="@string/app_name"
    ...
    >

As I mentioned above, be sure to delete the default app_name property from strings.xml

PHP用curl访问https

昨天用php改写here的api,在做微博登录的时候,需要curl一下微博的api获取用户信息,但是微博的api是https协议,刚开始死活都访问不了,查了半天,才整明白。解决办法如下:

  1. 下载CAcert.pem,在windows中最好下载打包成rar的文件再解压出来,然后在属性中解除限制
  2. 在php.ini中修改curl.cainfo为CAcert.pem的地址
  3. 重启php

Done