How do I programmatically switch theme?
The reason it works only for the frontend pages is that:


The System module implements hook_custom_theme() using the following code

function system_custom_theme() {
  if (user_access('view the administration theme') &amp;&amp; path_is_admin(current_path())) {
    return variable_get('admin_theme');
  }
}

The function that invokes that hook has the following code

$custom_themes = array_filter(module_invoke_all('custom_theme'), 'drupal_theme_access');
if (!empty($custom_themes)) {
  $custom_theme = array_pop($custom_themes);
}



In other words, the theme selected is the one returned from the last hook invoked, which in your case is system_custom_theme().
If you want that your module always sets its own custom theme, even for administrative pages, you need to tell Drupal to execute your hook implementation for last.

function hook_module_implements_alter(&amp;$implementations, $hook) {
  if ($hook == 'custom_theme') {
    // Move mymodule_custom_theme() to the end of the list. module_implements()
    // iterates through $implementations with a foreach loop which PHP iterates
    // in the order that the items were added, so to move an item to the end of
    // the array, we remove it and then add it.
    $group = $implementations['mymodule'];
    unset($implementations['mymodule']);
    $implementations['mymodule'] = $group;
  }
}


As side note, since the module would be override the theme set in admin/appearance, the module should give an indication of that in that page.

As for using the Themekey module, that module doesn't override the theme for the administrative pages, since its hook implementation (themekey_custom_theme()) contains the following code.

  // don't change theme when ...
  if ((in_array('system', variable_get('themekey_compat_modules_enabled', array())) || !(variable_get('admin_theme', '0') &amp;&amp; path_is_admin($_GET['q']))) // ... admin area and admin theme set
     &amp;&amp; strpos($_GET['q'], 'admin/structure/block/demo') !== 0 // ... blocks demo
     &amp;&amp; strpos($_SERVER['SCRIPT_FILENAME'], 'cron.php') === FALSE // ... during cron run executed by cron.php
     &amp;&amp; strpos($_SERVER['SCRIPT_FILENAME'], 'drush.php') === FALSE // ... during cron run executed by drush
     &amp;&amp; (!defined('MAINTENANCE_MODE') || (MAINTENANCE_MODE != 'install' &amp;&amp; MAINTENANCE_MODE != 'update')) // ... during drupal installation or update
    ) {
  // …
}


The comment reads as "don't change theme when admin area and admin theme set." I would rather do what the Themekey module does, but since you are trying to set the theme in any case, the Themekey module would not work for your case.