[AIR接入Android 平台]处理res资源之文字国际化

一点声明:我的水平有限 这里仅仅只能写出我认为可行的方案 和 代码

文字国际化 其实是android编码的规范之一。但是不同的运营商提供的SDK 这块处理的都不一样。

就目前我接触过的平台来说。当乐 UC 91 360 算做得很好。

但是其他小平台  特别是有一个运营商 他们客户端技术才一个人。

都很不注重android文字国际化的问题。打包进ane的资源 布局文件XML必须是规范的国际化处理的。

否则就会在打包APK的时候报错。

例如下面:

一般这个错误在打包ANE的时候是不会报的。而在打包APK的时候就会报出来。

如图所示 这个错误主要是由于  ANE中的资源文件夹RES下的layout文件夹下的布局XML中的text 被SDK客户端程序员直接用代码写的。所以会直接写在layout的布局XML里面。

而一般android官方开发标准推荐更标准化的写法。把layout中的text的内容写入 value文件夹下的string.xml中。

而我们的ADT打包就是遵从这种标准。

例如layout某XML的一段:

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”账号 : “
android:textColor=”#A67D3D”
android:textSize=”17sp” />
红色部分的写法是错误的 正确的写法是 把红色部分变为:
<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@string/text001 “
android:textColor=”#A67D3D”
android:textSize=”17sp” />
在res下的value文件夹下的string.xml中加入:
<string name=”text001“>账号 :</string>
这样才是规范的res文件。
为了批量出来这种事情 我写了一个工具类
resHandle.as

[cc lang=”java”]
package
{
import flash.desktop.Clipboard;
import flash.desktop.ClipboardFormats;
import flash.desktop.NativeDragManager;
import flash.display.InteractiveObject;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.NativeDragEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.net.FileFilter;
import flash.net.FileReference;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.text.TextFormat;

import flashButton.backButton;

/**
*
* @author Rect 2013-4-16
*
*/
[SWF(width=”800″ , height=”600″)]
public class FileXMLHandle extends Sprite
{
private var sp:Sprite;
private var mapAry:Array = [];
private var test:TextField;
private var beginBtn:backButton;
private var SelectBtn:backButton;
private var outBtn:backButton;
private var textSize:TextField;
private var textQuality:TextField;
private var fileObj:FileReference = new FileReference();
private var selectedSaveFile:File;
private var fileArr:Array = [];
private var key:String;
public function FileXMLHandle()
{
super();
init();
}
private function init():void{
sp = new Sprite();
test = new TextField();
test.defaultTextFormat = (new TextFormat(“”,18,0xFFFFF));
test.text = “拖入此处”;
test.width = 400;
test.height = 400;
test.wordWrap = true;
test.multiline = true;

sp.addChild(test);
sp.graphics.beginFill(0x3CB371);
sp.graphics.drawRect(0,0,800,600);
sp.graphics.endFill();
this.addChild(sp);
sp.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onDragInHandler);
sp.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onDropHandler);

selectedSaveFile = new File();
selectedSaveFile.addEventListener(flash.events.Event.SELECT, onSelectedSaveFile);
var fileFilt:FileFilter = new FileFilter(“输出文件(*.xml)”, “*.xml”);
fileArr.push(fileFilt);

beginBtn = new backButton(“开始”);
beginBtn.x = 600,beginBtn.y = 110;
beginBtn.mouseEnabled = false;
beginBtn.addEventListener(MouseEvent.CLICK,onChick);
this.addChild(beginBtn);

SelectBtn = new backButton(“选择string.xml”);
SelectBtn.x = 600,SelectBtn.y = 10;
SelectBtn.addEventListener(MouseEvent.CLICK,onSelectFile);
this.addChild(SelectBtn);

outBtn = new backButton(“选择输出文件夹”);
outBtn.x = 600,outBtn.y = 60;
outBtn.addEventListener(MouseEvent.CLICK,onSelectPath);
this.addChild(outBtn);

}

private function onSelectedSaveFile(e:flash.events.Event):void
{
var str:String = selectedSaveFile.nativePath;
var __reg:RegExp = new RegExp(‘\\\\’, ”);

switch(key)
{
case “file”:
motherFileArys = str.replace(/\\/g,”/”);
break;

case “path”:
outPath = str.replace(/\\/g,”/”);
trace(outPath)
break;
}

if(motherFileArys && outPath)HandleMaps();
}
private var motherFileArys:String = null;
private var outPath:String = null;
private var _loaderImages:URLLoader = new URLLoader();
private var stringXML:XML;
private var miscXML:XML;
private function HandleMaps():void{
_loaderImages.addEventListener(Event.COMPLETE,loaderInitListeners);
_loaderImages.load(new URLRequest(motherFileArys));
}

private function loaderInitListeners(evt:Event):void {
_loaderImages.removeEventListener(Event.COMPLETE,loaderInitListeners);
stringXML = XML(_loaderImages.data);
_loaderImages.close();

}

/**********************************/
private function onChick(ev:MouseEvent):void{

HandleMap();
}

private function onSelectFile(ev:MouseEvent):void{
key = “file”;
selectedSaveFile.browse(fileArr);
}

private function onSelectPath(ev:MouseEvent):void{
key = “path”;
selectedSaveFile.browseForDirectory(“请选择目录”);
}

private function textDown(ev:MouseEvent):void{
var text:TextField = ev.currentTarget as TextField;
text.text = “”;
}
protected function onDragInHandler(event : NativeDragEvent) : void
{
var transferable :Clipboard = event.clipboard;
if(transferable.hasFormat(ClipboardFormats.FILE_LIST_FORMAT))
{
var files : Array = transferable.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
if(files)
{
var file : File = File(files[0]);

if(file && file.name.indexOf(“.xml”) >= 0 || file && file.name.indexOf(“.XML”) >= 0)
{
NativeDragManager.acceptDragDrop(event.currentTarget as InteractiveObject);
}
}

}
}

private var motherFileAry:Array = [];
private var sonFileAry:Array = [];
private var xmlHead:String = ‘‘;
protected function onDropHandler(event : NativeDragEvent) : void
{
motherFileAry = [];
sonFileAry = [];
var transferable :Clipboard = event.clipboard;
var files : Array = transferable.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
if(files)
{
var file :File;
for(var t:int = 0;t{stringArr[t]});
}

var filePath:String = motherFileArys ;
var f:FileStream = new FileStream();
var fl:File = new File(filePath);

f.open(fl,FileMode.WRITE);
var xmlStr1:String = stringXML.toString();
var pattern1:RegExp = /\n/g;
xmlStr1=xmlStr1.replace(pattern1, “\r\n”);
f.writeUTFBytes(String(xmlHead+”\r\n”+ xmlStr1));
f.close();

}

private function loaderInitListener(evt:Event):void {

_loaderImage.removeEventListener(Event.COMPLETE,loaderInitListener);

var xml:XML = XML(_loaderImage.data);

walk(xml);

makeFile(xml);

HandleMap();
}

private function makeFile(str:XML):void{

var filePath:String = (sonFileAry.splice(0,1)) ;
var f:FileStream = new FileStream();
var fl:File = new File(filePath);

f.open(fl,FileMode.WRITE);

var xmlStr:String = str.toString();
var pattern:RegExp = /\n/g;
xmlStr=xmlStr.replace(pattern, “\r\n”);
f.writeUTFBytes(String(xmlHead+”\r\n”+ xmlStr));

f.close();

}

private var stringArr:Array = [];
private var stringName:Array = [];
private var stringLen:int = 0;

private function walk( node:XML ):void {

var androidNS:Namespace = new Namespace(“android”,”http://schemas.android.com/apk/res/android”);
node.addNamespace(androidNS);

// Loop over all of the child elements of the node
for each ( var element:XML in node.elements( ) ) {
// Output the label attribute
var attributes:XMLList = element.attributes( );

for(var t:int = 0;t<100;t++) { if(!attributes[t]) break; var str:String = attributes[t] ; var pattern4:RegExp=/[\u4e00-\u9fa5]/; if(pattern4.test(str)) { stringArr.push(str); stringName.push("DW_string_" + stringLen); attributes[t] = "@string/DW_string_" + stringLen.toString(); stringLen++; } } walk( element ); } } } } [/cc] Buton [cc lang="java"] package flashButton { import flash.display.Sprite; import flash.events.MouseEvent; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; public class backButton extends Sprite { private var _buttonName:String; private var _szWide:Number; private var _szHeight:Number; private var _Color:int; public function backButton( buttonName:String, szWide:Number = 180, szHeight:Number = 40, Color:int = 0xFFFFFF) { _buttonName = buttonName; _szWide = szWide; _szHeight = szHeight; _Color = Color; init(); } private var _text:TextField; private var _textFormat:TextFormat; private function init():void{ _text = new TextField(); _text.mouseEnabled = false; _text.text = _buttonName; _text.x = 2; _text.y = 2; _text.width = _szWide-5; _text.height = _szHeight-5; _text.autoSize = TextFieldAutoSize.CENTER; _textFormat = new TextFormat(); _textFormat.size = 25; _textFormat.color = 0;//0x228b22; _text.setTextFormat(_textFormat); addChild(_text); this.graphics.beginFill(_Color,.9); this.graphics.drawRoundRect(0,0,_szWide,_szHeight,5,5); this.graphics.endFill(); this.addEventListener(MouseEvent.ROLL_OVER,onMouseOver); this.addEventListener(MouseEvent.ROLL_OUT,onMouseOut); } private function onMouseOut(ev:MouseEvent):void{ this.graphics.clear(); this.graphics.beginFill(_Color,.9); this.graphics.drawRoundRect(0,0,_szWide,_szHeight,5,5); this.graphics.endFill(); } private function onMouseOver(ev:MouseEvent):void{ this.graphics.clear(); this.graphics.beginFill(0xeedd82,.9); this.graphics.drawRoundRect(1,1,_szWide-1,_szHeight-1,5,5); this.graphics.endFill(); } } } [/cc] 使用方式: A.选择 要处理的资源文件 res/value/string.xml B.选择输出文件夹(用来输出处理过的布局xml) C.拖动 res/layout下的所有XML到程序界面 D.点击开始 E.结束后把输出文件夹的XML复制到res/layout下 完工。。 PS:这里只针对中文 一般英文的比较少 手动修改就是了

《[AIR接入Android 平台]处理res资源之文字国际化》有18个想法

  1. 兄弟
    这个正则表达式为什么
    var __reg:RegExp = new RegExp(‘\\\’, ”);
    是三个\\\?是二个还是四个\才对吧

  2. 不知道为什么,在使用百度推送3.0SDK进行ANE打包后,按照前面的方法进行了资源本地化,可在生成APK的时候还是出错了,出错是

    创建文件出错
    aapt tool failed:invalid resource directory name:c:\user\xxx\AppData\Local\temp\xxx-xxx…\res/value

    2.4的SDK打包,生成APK都一切正常

  3. 能不能集成一个百度推送啊,,搞了好久,始终有问题哎,,

  4. 资源没处理好.资源本地化已经OK,但是少部分资源被清空了,查找几字节的资源文件 在原来的地方再copy过去.或者您修改下资源本地化的代码.@JHM

  5. aapt tool failed:invalid resource directory name:c:\xxx..xxx\res/value
    在打包ANE时,在Android-ARM目录下有res\value\string.xml并且,对相应字符串都作了配置,不知道是何原故?

  6. 错误信息不完整 我估计是你资源处理出错了。你看看string.xml下的每一项是否配错@JHM

  7. 你好,能针对百度推送进行一次ANE打包嘛,实在是搞不定,照着这里面的教程都看了几遍,始终有问题。

  8. 你好!我会报这种资源不匹配的错误,No resource found that matches the given name (at 'background' with value '@drawable/pop_up_box_bg').是什么原因,还有一个

    9-patch image C:\Users\Administrator\AppData\Local\Temp\1\be2cfe19-7135-4b4c-bce5-be5b3588e78d\res\drawable-hdpi\egame_close_button_normal.9.png malformed.这种图片格式还会报错

  9. aapt tool failed:invalid resource directory name:E:\flash bulider4.6.0\sdks\4.6.0\lib\android\lib\resources\captive_runtime/res\drawable-xxhdpi
    我用的是4.6 sdk,win8 64位

    1. @leesren, 使用android SDK的一款9-patch工具对每一个9.png文件处理一下.

  10. 你好,我现在遇到的问题是使用自己封好的ane打包出APK,可以监听到init回调回来的信息,从这之后到login期间(login trace出来的信息在scout中也没有显示出来)APK会自动停止运行。我做的是金山的SDK,不知道Rect你有没有做过,给我参考参考。。

  11. 其实还有一个解决办法:将AIRSDK/lib/android/bin/下的aapt重命名为aapt_bin,然后写一个简单的脚本,命名为aapt,再去调用aapt_bin,调用过程中,将参数-z去掉就OK了:
    #!/bin/sh
    argc=0
    for curarg in “$@”
    do
    newargs[$argc]=”${curarg}”
    if [ “${curarg}” == “-z” ];then
    continue;
    fi
    echo ${curarg}
    argc=$(expr $argc + 1)
    done

    echo $@
    echo ${newargs[@]}
    “${0}_bin” “${newargs[@]}”

    如果是windows下的话,做法差不多,不要要用vs写一个可执行程序了。

JHM进行回复 取消回复

邮箱地址不会被公开。 必填项已用*标注