2013-11-14 2 views
4

Я разрабатываю плагин Cordova с активностью, и мне нужно получить доступ к приложению R.layout из этой операции, чтобы я мог позвонить setContentView.Плагин импорта активности плагина Phonegap

В настоящее время я делаю это, сделав import com.example.hello.R, а затем на onCreate method I call setContentView (R.layout.mysurfaceview) `:

Проблема в том, что мой плагин будет работать только если имя приложения является com.example.hello, но Мне нужно установить мой плагин в разных приложениях без ручного импорта.

Есть ли способ сделать общий импорт, что-то вроде import <appName>.R или любые другие способы сделать это?

ответ

13

Вы можете вызвать пул ресурсов приложения во время выполнения и обратиться к идентификатору по имени, используя функцию Resources.getIdentifier(). Эта функция требует имя ресурса, тип и имя пакета. Например:

String package_name = getApplication().getPackageName(); 
Resources resources = getApplication().getResources(); 
setContentView(resources.getIdentifier("my_activity_layout", "layout", package_name)); 

где «my_activity_layout» - это имя XML-файла макета. Вы можете также ссылаться на строки, чертежи и другие ресурсы таким же образом. Когда у вас есть этот бит кода в вашей деятельности, вы можете назначить файл макета активности в качестве исходного файла в файле plugin.xml и установить его для копирования в папку res/layout.

<source-file src="path/to/your/layout/file.xml" target-dir="res/layout"/> 

Отъезд в Phonegap Plugin Specification, если у вас есть какие-либо другие вопросы об использовании исходного файла назначения.

+0

Я думаю, что крючок слишком сложный для этого и может не работать с сборкой phonegap. Использование resources.getIdentifier отлично работает. – QuickFix

1

Я бы использовал cordova CLI hook для изменения инструкции импорта java во время сборки, возможно, путем разбора имени пакета из AndroidManifest или config.xml.

Я не верю, что есть способ сделать подстановочный пакет, как вы спрашиваете.

+0

Кто-нибудь нашел решение для этого? Я столкнулся с теми же проблемами здесь! – Sebastian

+0

@ Себастьян, ты попробовал написать крючок? – mooreds

+0

: На самом деле я никогда не делал этого раньше ... Можете ли вы дать мне подсказку, с чего начать? Благодаря! – Sebastian

1

Благодаря ответ mooreds'S, Вы можете создать after_plugin_install крюк в плагине как ниже

#!/usr/bin/env node 
/* 
A hook to add R.java to the draw activiy in Android platform. 
*/ 


var fs = require('fs'); 
var path = require('path'); 

var rootdir = process.argv[2]; 

function replace_string_in_file(filename, to_replace, replace_with) { 
    var data = fs.readFileSync(filename, 'utf8'); 
    var result = data.replace(to_replace, replace_with); 
    fs.writeFileSync(filename, result, 'utf8'); 
} 

var target = "stage"; 
if (process.env.TARGET) { 
    target = process.env.TARGET; 
} 

    var ourconfigfile = path.join("plugins", "android.json"); 
    var configobj = JSON.parse(fs.readFileSync(ourconfigfile, 'utf8')); 
    // Add java files where you want to add R.java imports in the following array 

    var filestoreplace = [ 
     "platforms/android/src/in/co/geekninja/plugin/SketchActivity.java" 
    ]; 
    filestoreplace.forEach(function(val, index, array) { 
     if (fs.existsSync(val)) { 
      console.log("Android platform available !"); 
      //Getting the package name from the android.json file,replace with your plugin's id 
      var packageName = configobj.installed_plugins["in.co.geekninja.Draw"]["PACKAGE_NAME"]; 
      console.log("With the package name: "+packageName); 
      console.log("Adding import for R.java"); 
      replace_string_in_file(val,"package in.co.geekninja.plugin;","package in.co.geekninja.plugin;\n\nimport "+packageName+".R;"); 

     } else { 
      console.log("No android platform found! :("); 
     } 
    }); 

и добавьте следующую строку между <platform name="android"> ... </platform> тегом

<hook type="after_plugin_install" src="hooks/after_plugin_install/hook-add-r-import.js" /> 
0

Как указано @insomniac, крючки могут использоваться для замены содержимого исходного файла, чтобы удалить неправильный импорт и/или добавить правильный импорт ресурсов.

Основываясь на его ответе, я мог бы создать скрипт, который сделает это, не указывая файлы. Он пытается найти исходные файлы (с расширением .java), удаляет уже импортированный им импорт ресурсов и затем вставляет необходимые ресурсы (при необходимости), используя имя пакета приложения Cordova.

Это сценарий:

#!/usr/bin/env node 

/* 
* A hook to add resources class (R.java) import to Android classes which uses it. 
*/ 

function getRegexGroupMatches(string, regex, index) { 
    index || (index = 1) 

    var matches = []; 
    var match; 
    if (regex.global) { 
     while (match = regex.exec(string)) { 
      matches.push(match[index]); 
      console.log('Match:', match); 
     } 
    } 
    else { 
     if (match = regex.exec(string)) { 
      matches.push(match[index]); 
     } 
    } 

    return matches; 
} 

module.exports = function (ctx) { 
    // If Android platform is not installed, don't even execute 
    if (ctx.opts.cordova.platforms.indexOf('android') < 0) 
     return; 

    var fs = ctx.requireCordovaModule('fs'), 
     path = ctx.requireCordovaModule('path'), 
     Q = ctx.requireCordovaModule('q'); 

    var deferral = Q.defer(); 

    var platformSourcesRoot = path.join(ctx.opts.projectRoot, 'platforms/android/src'); 
    var pluginSourcesRoot = path.join(ctx.opts.plugin.dir, 'src/android'); 

    var androidPluginsData = JSON.parse(fs.readFileSync(path.join(ctx.opts.projectRoot, 'plugins', 'android.json'), 'utf8')); 
    var appPackage = androidPluginsData.installed_plugins[ctx.opts.plugin.id]['PACKAGE_NAME']; 

    fs.readdir(pluginSourcesRoot, function (err, files) { 
     if (err) { 
      console.error('Error when reading file:', err) 
      deferral.reject(); 
      return 
     } 

     var deferrals = []; 

     files.filter(function (file) { return path.extname(file) === '.java'; }) 
      .forEach(function (file) { 
       var deferral = Q.defer(); 

       var filename = path.basename(file); 
       var file = path.join(pluginSourcesRoot, filename); 
       fs.readFile(file, 'utf-8', function (err, contents) { 
        if (err) { 
         console.error('Error when reading file:', err) 
         deferral.reject(); 
         return 
        } 

        if (contents.match(/[^\.\w]R\./)) { 
         console.log('Trying to get packages from file:', filename); 
         var packages = getRegexGroupMatches(contents, /package ([^;]+);/); 
         for (var p = 0; p < packages.length; p++) { 
          try { 
           var package = packages[p]; 

           var sourceFile = path.join(platformSourcesRoot, package.replace(/\./g, '/'), filename) 
           if (!fs.existsSync(sourceFile)) 
            throw 'Can\'t find file in installed platform directory: "' + sourceFile + '".'; 

           var sourceFileContents = fs.readFileSync(sourceFile, 'utf8'); 
           if (!sourceFileContents) 
            throw 'Can\'t read file contents.'; 

           var newContents = sourceFileContents 
            .replace(/(import ([^;]+).R;)/g, '') 
            .replace(/(package ([^;]+);)/g, '$1 import ' + appPackage + '.R;'); 

           fs.writeFileSync(sourceFile, newContents, 'utf8'); 
           break; 
          } 
          catch (ex) { 
           console.log('Could not add import to "' + filename + '" using package "' + package + '". ' + ex); 
          } 
         } 
        } 
       }); 

       deferrals.push(deferral.promise); 
      }); 

     Q.all(deferrals) 
      .then(function() { 
       console.log('Done with the hook!'); 
       deferral.resolve(); 
      }) 
    }); 

    return deferral.promise; 
} 

Просто добавьте как after_plugin_install крюка (для Android платформы) в вашем plugin.xml:

<hook type="after_plugin_install" src="scripts/android/addResourcesClassImport.js" /> 

Надеется, что это помогает кто-то!

Смежные вопросы