-
Notifications
You must be signed in to change notification settings - Fork 237
/
extensions.txt
1516 lines (1067 loc) · 59.7 KB
/
extensions.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Extending the Rhodes Framework
## Introduction
There are three ways to extend Rhodes. You can add to the Ruby gems supported by Rhodes ("Rhodes extensions"). You can create new "native extensions" in the underlying SDK for a given smartphone operating system. You can extend the types of views available in Rhodes ("native extensions").
## Ruby Extensions
### Supported extensions and libraries
To keep Rhodes lightweight we left out some libraries.
Our C/C++ implementation is based on original Ruby C code, 1.9 release.
Our Java implementation is based on [XRuby](http://xruby.com), which supports Ruby 1.8 (We didn't use JRuby because it is substantially bigger and required version of java which is not available on most of the target mobile platforms).
Both implementations support such core classes and module as:
<i>
BasicObject, Object, Module, Class, Integer, Float, Numeric, Bignum, Rational, Complex, Math, String, StringScanner, StringIO,
Array, Hash, Struct, Regexp, RegexpError, MatchData, Data, NilClass, TrueClass, FalseClass, Comparable, Enumerable, Enumerator,
Converter, Marshal, IO, Dir, Time, Date, Signal, Mutex, Thread, ThreadGroup, Process, Fiber, FiberError, Method, UnboundMethod,
Binding, RubyVM, GC, Exception, SystemExit, fatal, SignalException, Interrupt, StandardError, TypeError, ArgumentError, IndexError,
KeyError, RangeError, ScriptError, SyntaxError, LoadError, NotImplementedError, NameError, NoMethodError, RuntimeError,
SecurityError, NoMemoryError, EncodingError, CompatibilityError, SystemCallError, Errno, ZeroDivisionError, FloatDomainError,
IOError, EOFError, ThreadError
</i>
We are using Rubinius specs to test Ruby compatibility across different platforms.
### JSON library support
For parsing use Rho::JSON.parse, no extension required.
Ruby code example:
:::ruby
parsed = Rho::JSON.parse("[{\"count\":10}]")
For generate use JSON extension.
Add to build.yml:
extensions: ["json"]
In case of several extensions, insert space after extension name and comma:
extensions: ["json", "net-http"]
Ruby code example:
:::ruby
require 'json'
json_data = ::JSON.generate(some_object)
See JSON tests in [Rhodes System API Samples application](http://github.com/rhomobile/rhodes-system-api-samples/tree/master/app/JsonTest/controller.rb) as an example.
### XML handling
There are two ways of handling XML directly in Rhodes. The Rexml library and the much faster RhoXML library.
#### Rexml
Add to build.yml:
extensions: ["rexml", "set"]
Ruby code example:
:::ruby
require 'rexml/document'
file = File.new("bibliography.xml")
doc = REXML::Document.new(file)
puts doc
#### RhoXML
This is a reduced version of rexml. Rhoxml has the same syntax as rexml, but smaller in size and faster. For Blackberry this is the only choice, because rexml is too slow.
Change rexml to rhoxml in build.yml:
extensions: ["rhoxml"]
No more changes required.
Rhoxml limitations:
1. Decoding xml text is not fully implemented. See document.rb line 503 (Text::unnormalize). Need to implement non regular expression decoding.
2. No DTD, validation and formatters support
3. Support only elements and attributes. No cdata, comments, etc.
#### XML Stream parser
To process xml faster (without building DOM xml tree in memory) you can use StreamParser:
:::ruby
class MyStreamListener
def initialize(events)
@events = events
end
def tag_start name, attrs
#puts "tag_start: #{name}; #{attrs}"
@events << attrs if name == 'event'
end
def tag_end name
#puts "tag_end: #{name}"
end
def text text
#puts "text: #{text}"
end
def instruction name, instruction
end
def comment comment
end
def doctype name, pub_sys, long_name, uri
end
def doctype_end
end
def attlistdecl element_name, attributes, raw_content
end
def elementdecl content
end
def entitydecl content
end
def notationdecl content
end
def entity content
end
def cdata content
#puts "cdata: #{content}"
end
def xmldecl version, encoding, standalone
end
end
def parse_xml(str_xml)
@events = []
list = MyStreamListener.new(@events)
REXML::Document.parse_stream(str_xml, list)
...
It supported in RhoXml and Rexml extensions. For example see : [`<rhodes>\spec\phone_spec\app\spec\xml_spec.rb`](https://github.com/rhomobile/rhodes/blob/master/spec/phone_spec/app/spec/xml_spec.rb) ("should stream parse" spec) and rexml stream parser documentation
### Barcode
Add to build.yml:
extensions: ["Barcode"]
See details [here](device-caps#barcode).
### net/http
Add to build.yml:
extensions: ["net-http", "thread", "timeout", "uri"]
### hmac
Add to build.yml:
extensions: ["hmac", "digest", "digest-sha1"]
Example:
:::ruby
require 'base64'
require 'hmac-sha1'
def test_hmac
key = '1234'
signature = 'abcdef'
hmac = HMAC::SHA1.new(key)
hmac.update(signature)
puts Rho::RhoSupport.url_encode(Base64.encode64("#{hmac.digest}\n"))
end
### FileUtils
Add to build.yml:
extensions: ["fileutils"]
DryRun, NoWrite and Verbose are commented out modules since they using `eval` function.
Blackberry is not supported.<br/>
Use Ruby class `Dir` whenever possible.
### Notes on Ruby standard library support
For iPhone the Date class is supported
:::ruby
require 'date'
puts Date.today.to_s
For Blackberry Date is still not supported. Use this instead:
:::ruby
require 'time'
Time.now.strftime('%Y-%m-%d')
### Adding Ruby Extension Libraries to Your Rhodes Application
Create folder 'extensions' under application root.
Copy folder with Ruby library to 'extensions' folder. (This will work for "pure ruby" extensions. Extensions which implemented in c/c++ or such you will have to compile for the target platform and link with Rhodes.)
Add extension with folder library name to build.yml:
extensions: ["myext"]
This library will be available for require:
:::ruby
require 'myext'
Using this technique you can easily remove extension from application or include some extension for particular platform:
iphone:
extensions: ["mspec", "fileutils"]
wm:
extensions: ["json"]
### Adding Libraries to Your Rhodes Application
During the course of your app development you might need to add an external ruby library with extra features that the rhodes framework doesn't provide. While we don't guarantee that all ruby libraries will work on the mobile device, you can follow the steps below to add and test libraries as needed.
In Rhodes, the require path is relative to the "app" subdirectory, since this is what gets bundled with the rhodes client.
Assuming your application is called "mynewapp", create a directory under app called lib (or whatever you wish to call it):
:::term
$ cd mynewapp
$ mkdir app/lib
Add your ruby files to this directory:
:::ruby
$ cp /path/to/my_lib.rb app/lib/my_lib.rb
Now, in your application (controller.rb for example), you can load this library like the following:
:::ruby
require 'rho/rhocontroller'
require 'lib/my_lib'
class TicketController < Rho::RhoController
def use_lib
@a = MyLib.new
...
end
end
Please note that "rubygems" are not loaded on the device Ruby VM because of size constraints, therefore all third-party ruby library source files must be put into the lib directory as described above.
### Adding Libraries to Rhodes Framework
There are two ways to add Ruby libraries to the Rhodes framework, essentially dependent upon how you choose to build your Rhodes application.
If you are using Rhodes via the RubyGems installation, you must add external Ruby libraries to your RubyGems installation directory for the 'rhodes-framework' gem. Your RubyGems installation directory can be found with `gem env` in a terminal.
For example, a user on Linux might place additional libraries in the following directory:
/usr/local/lib/ruby/gems/1.8/gems/rhodes-x.x.x/lib/framework
Similarly, a user on Mac OSX 10.5 might place them here:
/Library/Ruby/Gems/1.8/gems/rhodes-x.x.x/lib/framework
For Windows, this location might be:
C:/ruby/lib/ruby/gems/1.8/gems/rhodes-x.x.x/lib/framework
If you are using a clone of the Rhodes Git repository, you can put additional libraries in the following directory (preferably on your own github fork):
<rhodes-clone>/lib/framework
Including the library into your application is simple once the library is in the proper directory.
Assuming the library has been added to the correct location, require the library from a controller in your Rhodes application:
:::ruby
require 'libname'
You can now use the added library to access additional functionality not provided by the Rhodes framework.
NOTE: Once again, it should be mentioned that not all libraries are guaranteed to work with Rhodes.
## Encryption libraries
### digest - based extensions
digest, digest-sha1, digest-md5
Add to build.yml:
extensions: ["digest", "digest-sha1", "digest-md5"]
NOTE: digest should be included in extensions list to use digest-base libraries
### OpenSSL - based libraries
openssl, ezcrypto
Add to build.yml:
extensions: ["openssl.so", "openssl", "digest-sha2", "ezcrypto"]
digest-sha2
Add to build.yml:
extensions: ["openssl.so", "openssl", "digest", "digest-sha2" ]
NOTE: openssl.so is native c-library and should be included in extensions list to use openssl-base libraries
## Native Extensions
Starting from 2.0, Rhodes supports native extensions for Android, iPhone, WM and BlackBerry platforms. Native extensions are extensions written in the native language for the platform (C/C++/ObjC for iPhone, C/C++/Java for Android, C/C++ for WM, Java for Blackberry).
## Generating a Native Extension Template
The rhogen extension command allows you to create a native extension template for your Rhodes application. This template contains build scripts, projects, and native source code for the functions calc_summ and native_process_string, which you can use as templates to create your own native extension functions.
Before you use the rhogen extension command, you must have or you must create a Rhodes application from which you will call the native extension. You can [generate a Rhodes application](generator) from the command line or from RhoStudio.
Then, on the command line, navigate to the main folder in your Rhodes application. Run the following command:
:::term
rhogen extension yourextension
where `yourextension` is the name you want to use for your native extension.
This command will create two folders in your application folder:
* `yourextensionTest`, which contains a test controller and page for the generated native extension.
* `extensions`, which contains the generated native extension source code for the iPhone, Android, Windows Mobile, and Blackberry platforms.
### Understanding the Generated Native Extension Test Implementation
In your applications `app` folder is a folder named `yourextensionTest`. It contains two files that have a test implementation of the generated native extension example functions:
* controller.rb - An example of application controller code with execution of the generated extension code.
* index.erb - A page that executes the application controller.
The controller.rb is a simple Ruby controller file that calls the generated native extension functions of calc_summ and process_string. It has a function, run_test, that calls the calc_summ native function to calculate a sum, then uses an Alert popup to show the sum via the process_string native function.
:::ruby
require 'rho/rhocontroller'
require 'yourextension'
class YourextensionTestController < Rho::RhoController
@layout = :simplelayout
def index
render :back => '/app'
end
def run_test
sum = Yourextension.calc_summ(3,7)
Alert.show_popup YourextensionModule::YourextensionStringHelper::process_string('test')+sum.to_s
render :action => :index, :back => '/app'
end
end
The index.erb provides a page where you can click a link to run the run_test function.
:::html
<h3>Yourextension Extension Test</h3>
<div>
<%= link_to '[Run Yourextension test]', { :action => :run_test }%><br/>
</div>
## Understanding the Generated Native Extension Code
The extensions folder has the following contents.
:::term
yourextension - A folder named for your extension.
ext.yml - The native extension configuration file. It contains the library name, java entry point (class name for BB), C entry point, etc.
yourextension.rb - The extension Ruby code. This file contains Ruby classes that you wish to execute from your native code; it has the generated Ruby class YourextensionStringHelper.
All files named in this folder will be added to build extent "ext" folder and file.
ext - The folder with the extension sources for the native build.
build - A unix based build script (for Mac OS).
build.bat - A Windows based build script (for MS Windows).
<yourextension> - The folder containing the shared and platform folders.
shared - The folder with the shared code (this is used by all platforms except Blackberry). Contains the interface for the native extension.
platform - The folder with the platform dependent code, This contains the native extension code for your platform, which you will rewrite for your native extension.
To create your native extension, you will rewrite code within:
* the `shared` folder, which contains the interface for your native extension.
* the `platform` folder, which contains the source code for your native extension.
## Rewriting the Generated Native Extension Interface Code
The `shared` folder, within `extensions/yourextension/ext/yourextension`, contains the interface code for your native extension that is used by all platforms except for Blackberry. It contains the following folders and files.
:::term
ruby - The folder with the native-Ruby code wrapper. We use SWIG to generate the C wrapper code from the Ruby interface file.
yourextension.i - The Ruby interface declaration for native code
<yourextension_wrap.c - wrapper code for *.i file generated by SWIG
src - folder with native shared native code
yourextension.c - C file with main extension initialization function (native entry point) - also execute Ruby wrapper initialization code.
You need to:
* Rewrite the Interface file, yourextension.i, by changing the generated native extension function names to your native extension function names.
* Regenerate the wrapper file, yourextension_wrap.c, by running the SWIG command on the rewritten Interface file: `swig -ruby yourextension.i`.
Here is the yourextension.i file that is generated by the rhogen extension command. You would replace the calc_summ and native_string_process interfaces with interfaces for your native extension functions.
:::ruby
/* yourextension.i */
%module Yourextension
%{
#include "ruby/ext/rho/rhoruby.h"
extern VALUE yourextension_native_process_string(const char* str);
extern int yourextension_calc_summ(int x, int y);
#define native_process_string yourextension_native_process_string
#define calc_summ yourextension_calc_summ
%}
extern VALUE native_process_string(const char* str);
extern int calc_summ(int x, int y);
Suppose you generated code for a native extension that you named Accelerometer. You would have a file named Accelerometer.i that contains the references to the process_string and calc_summ functions that are generated by rhogen; you would replace these references with the references to your native extension code for Accelerometer. You would start with this code:
:::ruby
/* accelerometer.i */
%module Accelerometer
%{
#include "ruby/ext/rho/rhoruby.h"
extern VALUE accelerometer_native_process_string(const char* str);
extern int accelerometer_calc_summ(int x, int y);
#define native_process_string accelerometer_native_process_string
#define calc_summ accelerometer_calc_summ
%}
extern VALUE native_process_string(const char* str);
extern int calc_summ(int x, int y);
In this Accelerometer example, the native extensions are a start function and a get_readings function. You would rewrite the accelerometer.i as follows, replacing the generated functions of calc_summ and native_process_string with your start and get_readings functions.
:::ruby
/* accelerometer.i */
%module Accelerometer
%{
#include "ruby/ext/rho/rhoruby.h"
extern void accelerometer_get_readings(double *x, double *y, double *z);
extern void accelerometer_start(void);
#define get_readings accelerometer_get_readings
#define start accelerometer_start
%}
extern void get_readings(double *OUTPUT, double *OUTPUT, double *OUTPUT);
extern void start(void);
## Rewriting the Generated Native Extension Source Code for iPhone
The iPhone generated native extension code is contained in the following structure.
:::term
iphone - folder with iPhone native extension code
Rakefile - The build script for the iPhone platform.
yourextension.xcodeproj - The Xcode project file of iPhone specific code.
Classes - a folder with the iPhone native extension source code.
yourextension.h - header file
yourextension.m - iPhone specific code (implementation of native function declared in Ruby wrapper).
To create native extensions for the iPhone platform:
* Rewrite the generated Objective C files in the Classes folder, yourextension.h and yourextension.M, to implement your native extension.
* Add any new Objective C files that you create to the Xcode project for this native extension.
### Rewriting the Native Extension Objective C Header File
If you generate an Accelerometer native extension, you get the following header file (accelerometer.h) for the iPhone.
:::cplusplus
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
You could rewrite this header file to look like this for an accelerometer.
:::cplusplus
#import <UIKit/UIKit.h>
@interface Accel : UIViewController<UIAccelerometerDelegate>
{
}
- (void)start;
@end
### Rewriting the Native Extension Objective C Manifest File
If you generate an Accelerometer native extension, you get the following manifest file (accelerometer.m) for the iPhone.
:::cplusplus
#import "Accelerometer.h"
#include "ruby/ext/rho/rhoruby.h"
VALUE accelerometer_native_process_string(const char* str) {
NSString* os_string = @"<iOS>";
NSString* result_string = [os_string stringByAppendingString:[NSString stringWithUTF8String:str]];
result_string = [result_string stringByAppendingString:os_string];
VALUE result = rho_ruby_create_string([result_string UTF8String]);
return result;
}
int accelerometer_calc_summ(int x, int y) {
return (x+y);
}
You can rewrite the accelerometer.m file as follows to access the iPhone accelerometer functionality. Replace the stub code for accelerometer_native_process_string and accelerometer_calc_summ with your code: in this case, with native functions start and get_readings.
:::cplusplus
#import "Accelerometer.h"
// store the acceleration values
double gx,gy,gz;
// Reference this Objective C class.
Accel *accel;
@implementation Accel
-(void)start
{
// Initialize the accelerometer variables.
gx = gy = gz = 0;
// Set the update interval.
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:0.025];
// Set the delegate to this class, so the iPhone accelerometer will
// call you back on the delegate method.
[[UIAccelerometer sharedAccelerometer] setDelegate:self];
}
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
// Get the accelerometer values from the iPhone.
{
gx = acceleration.x;
gy = acceleration.y;
gz = acceleration.z;
}
@end
// This C function interfaces with the Objective C start function.
void accelerometer_start(void) {
// make sure we can only start this method once
static bool started = false;
if(!started) {
// Initialize the Objective C accelerometer class.
accel = [[Accel alloc] init];
// Start the accelerometer readings.
[accel start];
started = true;
}
}
// This C function allows us to get the readings from the accelerometer so
// they can be returned to the Ruby code.
void accelerometer_get_readings(double *x, double *y, double *z) {
*x = gx;
*y = gy;
*z = gz;
}
### Adding New Files to the Xcode Project
If you create any new files for your native extension, you must add them to the Xcode project. In Xcode, open yourextension.xcodeproj. Then add the new files to this project.
## Rewriting the Generated Native Extension Source Code for Android
The Android generated native extension code is contained in the following structure.
:::term
android - folder with Android specific code
Rakefile - build script for Android platform
ext_build.files - list of java files should be compiled
jni - folder with Android native code
src
yourextension.cpp - native Android code with implementation of native function declared in Ruby wrapper
src - folder with Java Android code
com
yourextension
yourextension.java - Android java code
### Rewrite the Generated Android Native Extension Java File
The folder in extensions/yourextension/ext/yourextension/platform/android/src contains a generated Java file, yourextension.java. This file contains the native extension code for the process_string function. Rewrite this code to reference your native extension function.
:::java
package com.yourextension;
public class Yourextension {
public static String processString(String str) {
return "<Android>" + str + "<Android>";
}
}
### Rewrite the Generated Android C++ Native Extension
Rewrite the C++ file for your native extension. This is where you implement the C function that is declared in the Interface file. You would also implement any Android native C++ code here.
The generated C++ file for Android, yourextension.cpp (within the folder extensions/yourextension/ext/yourextension/platform/android/jni/src) contains the C interfaces for the native_process_string function and the calc_summ functions. Rewrite that code for the interfaces for your native extension functions: rename the functions to match yours, redo their argument lists, etc.
:::cplusplus
#include <rhodes.h>
#include "rubyext/WebView.h"
#include <stdlib.h>
#include "ruby/ext/rho/rhoruby.h"
extern "C" VALUE yourextension_native_process_string(const char* str) {
JNIEnv *env = jnienv();
jclass cls = rho_find_class(env, "com/yourextension/Yourextension");
if (!cls) return rho_ruby_get_NIL();;
jmethodID mid = env->GetStaticMethodID( cls, "processString", "(Ljava/lang/String;)Ljava/lang/String;");
if (!mid) return rho_ruby_get_NIL();;
jstring objStr = env->NewStringUTF(str);
jstring jstr = (jstring)env->CallStaticObjectMethod(cls, mid, objStr);
env->DeleteLocalRef(objStr);
const char* buf = env->GetStringUTFChars(jstr,0);
VALUE result = rho_ruby_create_string(buf);
env->ReleaseStringUTFChars(jstr, buf);
return result;
}
extern "C" int yourextension_calc_summ(int x, int y) {
return (x+y);
}
### Add New C++ Files to Rakefile
You can code new C++ files; place them in the extensions/yourextension/ext/yourextension/platform/android/jni/src/ folder (the same folder containing yourextension.cpp). If you add new C++ files, add their file names to the list of C++ files in the Rakefile, which is in the folder extensions/yourextension/ext/yourextension/platform/android.
In the Rakefile, there is a section coded as follows:
:::term
task :all => :config do
src_files = []
src_files << $yourextensiondir + '/ext/yourextension/platform/android/jni/src/yourextension.cpp'
src_files << $yourextensiondir + '/ext/yourextension/shared/ruby/yourextension_wrap.c'
src_files << $yourextensiondir + '/ext/yourextension/shared/src/yourextension.c'
# build native part
build_extension('Yourextension', $arch, src_files)
# java part will be built automatically (java files should be listed in ext_build.files and ext.yml should be configured)
end
Add a src_files line for every new .cpp file that you add to your native extension project, such as:
:::term
src_files << $yourextensiondir + '/ext/yourextension/platform/android/jni/src/yournewfile.cpp'
### Add New Java Files to ext_build.files
You can code new Java files for your native extension; if you do so, place them in the extensions/yourextension/ext/yourextension/platform/android/src folder (the same folder containing yourextension.java). Then add that file to the list of Java files in ext_build.files, which is in the folder extensions/yourextension/ext/yourextension/platform/android.
This sample listing of ext_build.files shows that it already lists the generated native extenstion Java file.
:::term
ext/yourextension/platform/android/src/com/yourextension/Yourextension.java
### Make changes to application AndroidManifest.xml
You can specify changes to AndroidManifest.xml in the ext.yml file as a path to the files with the changes.
There are three formats recognized by the build system, depending on the file extension:
* .xml - xml file with common AndroidManifest.xml format; its tags will be merged into the final manifest.
* .erb - ruby templates which will be injected into the final manifest.
* .rb - ruby script which will run by manifest erb generator.
android:
manifest_changes:
- ext/yourextension/platform/android/AndroidManifestAdds.xml
- ext/yourextension/platform/android/ApplicationTagAdds1.erb
- ext/yourextension/platform/android/ApplicationTagAdds2.erb
- ext/yourextension/platform/android/ManifestTagAdds.erb
- ext/yourextension/platform/android/AndroidManifestScript.rb
#### XML
This is the simplest way, if you know how your manifest has to look. Add the final AndroidManifest.xml to the extension and specify it in ext.yml.
The build system will try to merge all the tags from the file into the final AndroidManifest.xml. Tags which exist in both Rhodes and extension manifest will be overwritten from the extension manifest.
android:
manifest_changes: ext/yourextension/platform/android/AndroidManifest.xml
#### ERB template
There are two common levels where additional definitions can be injected into AndroidManifest.xml.
* Application tag
* Manifest tag
To add additional definitions to the Application tag, the template name must fit the file name mask of `Application*.erb`, such as `ApplicationManifestAdds.erb`.
To add additional definitions to Manifest tag, the template name must fit the file name mask of `Manifest*.erb`.
There may be a number of templates of each type.
In the template, you may access manifest generator fields which holds common values used to generate the manifest.
Below is example of a broadcast receiver definition added to 'application' tag by rhoconnect-push extension:
:::xml
<receiver android:name="com.motsolutions.rhomobile.services.ans.test3.ANSBroadcastReceiver"
android:permission="com.motsolutions.cto.services.ans.permission.RECEIVE"
android:enabled="true">
<!-- Receive actual messages -->
<intent-filter>
<action android:name="com.motsolutions.cto.services.ans.action.RECEIVE" />
<category android:name='<%=@appPackageName%>' />
</intent-filter>
<!-- Receive registration ids -->
<intent-filter>
<action android:name="com.motsolutions.cto.services.ans.action.REGISTRATION" />
<category android:name='<%=@appPackageName%>' />
</intent-filter>
</receiver>
#### RB script
In case the methods listed above are not enough, you can write your own script that will change the values used to generate the manifest.
You can hove a single script per extension.
In the script, you may access the ERB generator instance as a local variable.
:::ruby
generator.permissions["#{generator.appPackageName}.permission.ANS"] = 'signature'
generator.usesPermissions << "#{generator.appPackageName}.permission.ANS"
generator.usesPermissions << 'com.motsolutions.cto.services.ans.permission.REGISTER'
#### ERB Manifest Generator
The following generator fields may be accessed from erb templates or scripts.
* javaPackageName - read-only string
* appPackageName - read-only string
* versionName - read-write string
* versionCode - read-write string
* installLocation - read-write string
* minSdkVer - read-write string
* maxSdkVer - read-write string
* permissions - hash of permission name/protectionLevel pairs
* usesPermissions - array of permission names
* usesLibraries - hash of library name/isRequired pairs
* screenOrientation - read-write string
* debuggable - read-write string (allows two values: 'true' or 'false')
* rhodesActivityIntentFilters - array of hashes with filter values. Each hash can contain next keys:
** :act - string, intent action name
** :cat - array of strings with category names
** :data - hash with data tag attributes (name/value pairs)
* manifestManifestAdds - array of strings with full paths to erb templates for 'manifest' tag
* applicationManifestAdds - array of strings with full paths to erb templates for 'application' tag
For more details about the values for the generator fields, refer to [Android Developer Documentation](http://developer.android.com/guide/topics/manifest/manifest-intro.html).
You may also look in your Rhodes installation under /platform/android/Rhodes/AndroidManifest.xml.erb to study how these values are used.
## Rewriting the Generated Native Extension Source Code for Windows Mobile
The Windows Mobile generated native extension code is contained in the following structure.
:::term
wm - folder with Windows Mobile specific code
Rakefile - build script for WM platform
<yourextension>.vcproj - Microsoft Visual Studio project file for the Windows Mobile native extension
src - folder with WM specific sources
<yourextension>_wm.h - header file
<yourextension>_wm.cpp - native code with implementation of native function declared in Ruby wrapper
### Rewrite the Generated Native Extension C++ Files
You will find the implementations of the Windows Mobile version of the native_process_string and the calc_summ functions in the files yourextension_wm.h and yourextension_wm.cpp, which are in the folder extensions/yourextension/ext/yourextension/platform/wm/src. Rewrite these files for your native extension functions: rename the functions to match yours, redo the argument lists, implement your native extension functionality, etc.
Sample listing of yourextension_wm.cpp:
:::cplusplus
#include <common/RhodesApp.h>
#include <logging/RhoLogConf.h>
#include <stdlib.h>
#include <windows.h>
#include <commctrl.h>
#include <RhoNativeViewManager.h>
#include "rubyext/WebView.h"
#include "ruby/ext/rho/rhoruby.h"
#include "yourextension_wm.h"
extern "C" VALUE yourextension_native_process_string(const char* str) {
const char block[] = "<WM>";
char* buf = NULL;
buf = (char*)malloc(strlen(str) + strlen(block)*2 + 1);
strcpy(buf, block);
strcat(buf, str);
strcat(buf, block);
VALUE result = rho_ruby_create_string(buf);
free(buf);
return result;
}
extern "C" int yourextension_calc_summ(int x, int y) {
return (x+y);
}
### Adding New Files to the Visual Studio Project
If you create any new C++ files for your native extension, save them in the same location as the generated C++ file yourextension_wm.cpp, in extensions/yourextension/ext/yourextension/platform/wm/src.
Open the Visual Studio project for your native extension: yourextension_wm.vcproj in extensions/yourextension/ext/yourextension/platform/wm. Add any new C++ files to this project.
## Rewriting the Generated Native Extension Source Code for Blackberry
The Blackberry generated native extension code is contained in the following structure.
:::term
bb - folder with Blackberry specific code
Rakefile - build script for BB platform
<yourextension>.files - list of Java files to be compiled
<yourextension>.jdp - Eclipse project (not required for a rake script build)
src - folder with BB specific Java sources
com
<yourextension>
<yourextension>.java - BB platform entry point class with implementation and registration of Ruby functions
Note: You do not use the Interface file or SWIG with Blackberry. But you will rewrite the generated native extension Java file.
### Rewrite the Generated Native Extension Java File
First, rewrite the Public functions, renaming them and changing the arguments for your native extension.
:::java
public String doProcessString( String str ) {
return "<BB>" + str + "<BB>";
}
public int doCalcSumm( int x, int y ) {
return (x+y);
}
Then, in the void run() method, rewrite the native_process_string and the calc_summ methods declared in the YourextensionClass.getSingletonClass().
## Creating Your Native Extension Without the Generator
You can also create a native extension without using the rhogen extension command. This means you will need to write the entire extension (source code, interface file, build scripts, etc.) from scratch.
In your Rhodes application folder, create a folder called "extensions". This is the folder that will contain all your native extesion code for your Rhodes application. Within the "extensions" folder, create a folder named for the extension that you are creating, such as "accelerometer". An example path for a Rhodes application named "accel" would be `accel/extensions/accelerometer`. And in that folder, create a folder called "ext."
### Create Your Extensions Configuration File
In the folder named according to your extension name, such as `accel/extensions/accelerometer`, create `ext.yml` file.
In this file, you have two lines to define your initialization function and your libraries. Here is an example for an accelerometer extension.
entry: Init_Accelerometer
libraries: [ "accelerometer" ]
The first line names the function that is the entry point into your extension; the function is named Init_Your-extension-name. This function is called when your Rhodes application starts, so it will contain all your initialization code for your extension.
The second line is the name of your library extension that holds your binary extensions that are compiled and integrated into your Ruby code. It is named after the name of your extension folder; in this example, it is named accelerometer.
You can have more that one library, in which case you would separate the libraries with commas:
libraries: [ "extension1", "extension2" ]
For Android you may add additional extension parameters within android section:
* rhodes_listener - Java class name which implements com.rhomobile.rhodes.extmanager.IRhoListener interface (used to handle Rhodes application UI events)
* manifest_changes - filename with Android manifest items (in form of common AndroidManifest.xml), this file will be joined with main AndroidManifest.xml
* adds - folder with any additional files for add to main application build folder (may contain resources, assets and shared libraries)
* source_list - filename with list of *.java files to build with main Rhodes application package.
Here is an example of an ext.yml file for an NFC extension. This example is taken from the Rhodes installation, located at [Rhodes root]/lib/extensions/Nfc.
entry: Init_Nfc
libraries: ["Nfc"]
android:
rhodes_listener: com.rhomobile.nfc.Nfc
manifest_changes: ext/nfc/platform/android/AndroidManifest.xml
adds: ext/nfc/platform/android/additional_files
source_list: ext/nfc/platform/android/ext_build.files
### Create Your Build Script
In the "ext" folder, such as `accel/extensions/accelerometer/ext`, you will create your build scripts and your native extension code.
Create a build script file. Name this file `build` for Macintosh and `build.bat` for Windows. This file executes a rake file that contains all your compiling commands for your extension. (You can instead put your compiling commands in the build file, but this chapter uses the Rakefile method.)
For the Macintosh, the build file contains:
#!/bin/sh
rake
For Windows, the build.bat file contains:
rake --trace
The above build scripts execute a Rakefile script which you create: this Rakefile compiles your extension code and produces the libraries. When Rhodes creates the final binary for your application, it will search for and link with the library that was generated for your extension. For an extension called `accelerometer`, the build script for iPhone and Android should be name the library `libaccelerometer.a`; for Windows, it should be named `accelerometer.lib`. The build script (in this case, in the Rakefile) should place the library in the folder named by TARGET_TEMP_DIR.
**NOTE: You do not need to use a rakefile. You can put your compiling commands in the build or build.bat scripts. The only requirement is that you have a file named build and that it is executable.
## Environment Variables Used in the Build Script
Before you build the build script (in this case, a Rakefile), you should be aware of the environmental variables that you can use in the script. These variables give you the path to the Rhodes root and information about your application platform. In the example used here, the Rakefile for the iPhone accelerometer uses several of these variables.
The following environment variables are used by all the platforms.
<table border="1">
<tr>
<td><code>TARGET_TEMP_DIR</code></td>
<td>Location to put your compiled library</td>
</tr>
<tr>
<td><code>RHO_PLATFORM</code></td>
<td>mobile platform for this application build. Possible values are 'iphone', 'android' and 'wm'</td>
</tr>
<tr>
<td><code>RHO_ROOT</code></td>
<td>point to the Rhodes installation root folder (the directory where rhobuild.yml is located)</td>
</tr>
<tr>
<td><code>TEMP_FILES_DIR</code></td>
<td>used for temporary files like object files</td>
</tr>
</table>
The following environment variables are available for Android.
<table border="1">
<tr>
<td><code>ANDROID_NDK</code></td>
<td>path to the Android NDK used by Rhodes</td>
</tr>
<tr>
<td><code>ANDROID_API_LEVEL</code></td>
<td>Android API level used by Rhodes</td>
</tr>
</table>
The following environment variables are available for Windows Mobile.
<table border="1">
<tr>
<td><code>VCBUILD</code></td>
<td>path to the vcbuild application in the Microsoft Visual Studio installation</td>
</tr>
</table>
The following environment variables are available for iPhone.
<table border="1">
<tr>
<td><code>PLATFORM_DEVELOPER_BIN_DIR</code></td>
<td>path to the platform developer bin directory</td>
</tr>
<tr>
<td><code>SDKROOT</code></td>
<td>path to the root of the used SDK - 3.0, 3.1</td>
</tr>
<tr>
<td><code>ARCHS</code></td>
<td>path to the platform developer bin directory</td>
</tr>
<tr>
<td><code>XCODEBUILD</code></td>
<td>contains the full name of the xcodebuild</td>