অ্যান্ড্রয়েড এবং আইওএসের জন্য একই সি ++ কোড কীভাবে ব্যবহার করবেন?


119

এনডিকে সহ অ্যান্ড্রয়েডের সি / সি ++ কোড এবং আইওএসটিভ-সি ++ সহ আইওএসের সমর্থন রয়েছে, সুতরাং আমি কীভাবে অ্যান্ড্রয়েড এবং আইওএসের মধ্যে ভাগ করা নেটিভ সি / সি ++ কোড সহ অ্যাপ্লিকেশন লিখতে পারি?


1
চেষ্টা cocos2d-X ফ্রেমওয়ার্ক
Glo

@glo ভাল লাগছে, তবে আমি ফ্রেমওয়ার্ক ছাড়া সি ++ ব্যবহার করে আরও জেনেরিক জিনিস খুঁজছি, "জেএনআই বাদে স্পষ্টতই"।
ademar111190

উত্তর:


272

হালনাগাদ.

আমি উত্তরটি লেখার চার বছর পরেও এই উত্তরটি বেশ জনপ্রিয়, এই চার বছরে অনেক কিছুই পরিবর্তিত হয়েছে, তাই আমি আমাদের বর্তমানের বাস্তবতাকে আরও ভালভাবে ফিট করার জন্য আমার উত্তর আপডেট করার সিদ্ধান্ত নিয়েছি। উত্তর ধারণা পরিবর্তন হয় না; বাস্তবায়ন কিছুটা বদলে গেছে। আমার ইংরেজিও বদলেছে, এতে অনেক উন্নতি হয়েছে, সুতরাং উত্তরটি এখন সবার কাছে আরও বোধগম্য।

রেপোটি একবার দেখুন যাতে আপনি নীচে প্রদর্শিত কোডটি ডাউনলোড করতে এবং চালাতে পারেন।

উত্তর

আমি কোডটি দেখানোর আগে দয়া করে নীচের চিত্রটিতে অনেক কিছু নিবেন।

খিলান

প্রতিটি OS এর UI এবং বিশেষত্ব রয়েছে, তাই আমরা এই বিষয়ে প্রতিটি প্ল্যাটফর্মের জন্য নির্দিষ্ট কোড লেখার মনস্থ করি। অন্যদিকে, সমস্ত লজিক কোড, ব্যবসায়ের নিয়ম এবং যে জিনিসগুলি ভাগ করা যায় সেগুলি আমরা সি ++ ব্যবহার করে লেখার ইচ্ছা করি, তাই আমরা প্রতিটি প্ল্যাটফর্মে একই কোডটি সংকলন করতে পারি।

চিত্রটিতে, আপনি নিম্ন স্তরের সি ++ স্তর দেখতে পাবেন see সমস্ত ভাগ করা কোড এই বিভাগে। সর্বোচ্চ স্তরটি নিয়মিত ওবজে-সি / জাভা / কোটলিন কোড, এখানে কোনও খবর নেই, শক্ত অংশটি মাঝের স্তর।

আইওএস পাশের মাঝারি স্তরটি সহজ; আপনাকে কেবলমাত্র Ojj-c এর বৈকল্পিকটি অবজেক্টিভ-সি ++ হিসাবে ব্যবহার করে বিল্ড করার জন্য আপনার প্রকল্পটি কনফিগার করতে হবে এবং এটি সমস্ত, আপনার সি ++ কোড অ্যাক্সেস রয়েছে।

জিনিসটি জাভা ভার্চুয়াল মেশিনের অধীনে অ্যান্ড্রয়েডে জাভা এবং কোটলিন উভয় ভাষা অ্যান্ড্রয়েডের পক্ষে শক্ত হয়ে উঠেছে। সুতরাং সি ++ কোড অ্যাক্সেসের একমাত্র উপায়টি জেএনআই ব্যবহার করছে , দয়া করে জেএনআই এর প্রাথমিক বিষয়গুলি পড়তে সময় নিন। ভাগ্যক্রমে, আজকের অ্যান্ড্রয়েড স্টুডিও আইডিইতে জেএনআই পক্ষের ব্যাপক উন্নতি হয়েছে এবং আপনি নিজের কোড সম্পাদনা করার সময় আপনাকে অনেকগুলি সমস্যা দেখানো হবে।

পদক্ষেপ দ্বারা কোড

আমাদের নমুনা একটি সহজ অ্যাপ্লিকেশন যা আপনি সিপিপিতে একটি পাঠ্য প্রেরণ করেন এবং এটি সেই পাঠ্যটিকে অন্য কোনও কিছুতে রূপান্তর করে ফেরত দেয়। ধারণাটিটি হ'ল, আইওএস "ওবজ-সি" প্রেরণ করবে এবং অ্যান্ড্রয়েড তাদের নিজ নিজ ভাষা থেকে "জাভা" প্রেরণ করবে এবং সিপিপি কোড অনুসরণ করে একটি পাঠ্য তৈরি করবে "সিপিপি << পাঠ্য প্রাপ্ত >> " কে হ্যালো বলেছে ।

ভাগ করা সিপিপি কোড

প্রথমত, আমরা ভাগ করা সিপিপি কোড তৈরি করতে যাচ্ছি, এটি করার মাধ্যমে আমাদের কাছে একটি সাধারণ হেডার ফাইল রয়েছে পদ্ধতি ঘোষণার সাথে কাঙ্ক্ষিত পাঠ্য প্রাপ্তি:

#include <iostream>

const char *concatenateMyStringWithCppString(const char *myString);

এবং সিপিপি বাস্তবায়ন:

#include <string.h>
#include "Core.h"

const char *CPP_BASE_STRING = "cpp says hello to %s";

const char *concatenateMyStringWithCppString(const char *myString) {
    char *concatenatedString = new char[strlen(CPP_BASE_STRING) + strlen(myString)];
    sprintf(concatenatedString, CPP_BASE_STRING, myString);
    return concatenatedString;
}

ইউনিক্স

একটি আকর্ষণীয় বোনাস হ'ল, আমরা লিনাক্স এবং ম্যাকের পাশাপাশি অন্যান্য ইউনিক্স সিস্টেমের জন্যও একই কোডটি ব্যবহার করতে পারি। এই সম্ভাবনাটি বিশেষত কার্যকর কারণ আমরা আমাদের ভাগ করা কোডটি দ্রুত পরীক্ষা করতে পারি, সুতরাং আমরা আমাদের মেশিন থেকে এটি কার্যকর করতে একটি মেইন সিপিপি তৈরি করতে যাচ্ছি এবং ভাগ করা কোডটি কাজ করছে কিনা তা দেখুন।

#include <iostream>
#include <string>
#include "../CPP/Core.h"

int main() {
  std::string textFromCppCore = concatenateMyStringWithCppString("Unix");
  std::cout << textFromCppCore << '\n';
  return 0;
}

কোডটি তৈরি করতে আপনাকে কার্যকর করতে হবে:

$ g++ Main.cpp Core.cpp -o main
$ ./main 
cpp says hello to Unix

আইওএস

এটি এখন মোবাইল দিকে বাস্তবায়ন করার সময়। যতক্ষণ না আইওএসের একটি সহজ ইন্টিগ্রেশন রয়েছে আমরা এটি দিয়ে শুরু করছি। আমাদের আইওএস অ্যাপ্লিকেশনটি একটি সাধারণ ওবজ-সি অ্যাপ্লিকেশন যা কেবল একটি পার্থক্য সহ; ফাইল .mmএবং না .m। অর্থাত্ এটি একটি ওবজ-সি ++ অ্যাপ্লিকেশন, কোনও ওজেজে-সি অ্যাপ্লিকেশন নয়।

একটি ভাল সংস্থায়, আমরা নিম্নলিখিত হিসাবে CoreWrapper.mm তৈরি:

#import "CoreWrapper.h"

@implementation CoreWrapper

+ (NSString*) concatenateMyStringWithCppString:(NSString*)myString {
    const char *utfString = [myString UTF8String];
    const char *textFromCppCore = concatenateMyStringWithCppString(utfString);
    NSString *objcString = [NSString stringWithUTF8String:textFromCppCore];
    return objcString;
}

@end

এই শ্রেণীর সিপিপি ধরণের এবং ওবজে-সি ধরণের এবং কলগুলিতে রূপান্তর করার দায়িত্ব রয়েছে। আপনি একবার ওজেজে-সি-তে যে কোনও ফাইল সিপিপি কোড কল করতে পারেন তা বাধ্যতামূলক নয়, তবে এটি সংগঠনটি রাখতে সহায়তা করে এবং আপনার র‍্যাপার ফাইলগুলির বাইরে আপনি একটি সম্পূর্ণ ওবিজে-সি স্টাইলযুক্ত কোড বজায় রাখেন, কেবল মোড়কের ফাইলগুলি সিপিপি স্টাইলযুক্ত হয়ে যায় ।

একবার আপনার মোড়ক সিপিপি কোডের সাথে সংযুক্ত হয়ে গেলে আপনি এটি স্ট্যান্ডার্ড ওবিজে-সি কোড হিসাবে ব্যবহার করতে পারেন, যেমন ভিউকন্ট্রোলার "

#import "ViewController.h"
#import "CoreWrapper.h"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UILabel *label;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString* textFromCppCore = [CoreWrapper concatenateMyStringWithCppString:@"Obj-C++"];
    [_label setText:textFromCppCore];
}

@end

অ্যাপটি কীভাবে দেখায় তা একবার দেখুন:

xcode আইফোন

অ্যান্ড্রয়েড

এখন সময় অ্যান্ড্রয়েড সংহতকরণের। অ্যান্ড্রয়েড গ্রেডলকে বিল্ড সিস্টেম হিসাবে ব্যবহার করে এবং সি / সি ++ কোডে এটি সিএমকে ব্যবহার করে। সুতরাং আমাদের প্রথমটি করা দরকার হ'ল গ্রেড ফাইলটিতে সিএমকে কনফিগার করা:

android {
...
externalNativeBuild {
    cmake {
        path "CMakeLists.txt"
    }
}
...
defaultConfig {
    externalNativeBuild {
        cmake {
            cppFlags "-std=c++14"
        }
    }
...
}

এবং দ্বিতীয় পদক্ষেপটি CMakeLists.txt ফাইল যুক্ত করা হয়:

cmake_minimum_required(VERSION 3.4.1)

include_directories (
    ../../CPP/
)

add_library(
    native-lib
    SHARED
    src/main/cpp/native-lib.cpp
    ../../CPP/Core.h
    ../../CPP/Core.cpp
)

find_library(
    log-lib
    log
)

target_link_libraries(
    native-lib
    ${log-lib}
)

সিএমকে ফাইলটি যেখানে আপনাকে প্রকল্পে যে সিপিপি ফাইল এবং শিরোলেখ ফোল্ডারগুলি যুক্ত করতে হবে তা আমাদের উদাহরণ হিসাবে উদাহরণস্বরূপ, আমরা CPPফোল্ডার এবং Core.h / .cpp ফাইল যুক্ত করছি। সি / সি ++ কনফিগারেশন সম্পর্কে আরও জানতে দয়া করে এটি পড়ুন।

এখন মূল কোডটি আমাদের অ্যাপের অংশ, সেতুটি তৈরি করার, জিনিসগুলি আরও সহজ এবং সংগঠিত করার জন্য আমরা জেভিএম এবং সিপিপির মধ্যে আমাদের মোড়ক হওয়ার জন্য কোয়াররাপার্পার নামে একটি নির্দিষ্ট শ্রেণি তৈরি করি:

public class CoreWrapper {

    public native String concatenateMyStringWithCppString(String myString);

    static {
        System.loadLibrary("native-lib");
    }

}

দ্রষ্টব্য এই শ্রেণীর একটি nativeপদ্ধতি রয়েছে এবং এটি নামের একটি নেটিভ গ্রন্থাগার লোড করে native-lib। এই লাইব্রেরিটি আমরা তৈরি করি, শেষ পর্যন্ত, সিপিপি কোডটি .soআমাদের APK এ এম্বেড করা শেয়ারড অবজেক্টে পরিণত হবে এবং এটি loadLibraryলোড হবে। অবশেষে, আপনি যখন নেটিভ পদ্ধতিতে কল করবেন, জেভিএম কলটি বোঝা লাইব্রেরিতে প্রেরণ করবে।

এখন অ্যান্ড্রয়েড ইন্টিগ্রেশনের সবচেয়ে অদ্ভুত অংশ হ'ল জেএনআই; আমাদের ক্ষেত্রে "নেটিভ- lib.cpp" ক্ষেত্রে নিম্নলিখিত হিসাবে একটি সিপিপি ফাইল দরকার:

extern "C" {

JNIEXPORT jstring JNICALL Java_ademar_androidioscppexample_CoreWrapper_concatenateMyStringWithCppString(JNIEnv *env, jobject /* this */, jstring myString) {
    const char *utfString = env->GetStringUTFChars(myString, 0);
    const char *textFromCppCore = concatenateMyStringWithCppString(utfString);
    jstring javaString = env->NewStringUTF(textFromCppCore);
    return javaString;
}

}

আপনি যে বিষয়টি প্রথমটি লক্ষ্য করবেন তা হ'ল extern "C"এই অংশটিটি আমাদের সিপিপি কোড এবং পদ্ধতি সংযোগের সাথে জেএনআই সঠিকভাবে কাজ করার জন্য প্রয়োজনীয়। এছাড়াও আপনি জেভিএম সঙ্গে কাজের ধরনে কিছু চিহ্ন JNI ব্যবহারসমূহ দেখতে হবে JNIEXPORTএবং JNICALL। এই বিষয়গুলির অর্থ বোঝার জন্য, একটি সময় নেওয়া এবং এটি পড়া প্রয়োজন , এই টিউটোরিয়াল উদ্দেশ্যে কেবল এই বিষয়গুলিকে বয়লারপ্লেট হিসাবে বিবেচনা করুন।

একটি উল্লেখযোগ্য জিনিস এবং সাধারণত প্রচুর সমস্যার মূল কারণ হ'ল পদ্ধতির নাম; এটি "জাভা_প্যাকেজ_ক্লাস_মোথডো" প্যাটার্নটি অনুসরণ করতে হবে। বর্তমানে অ্যান্ড্রয়েড স্টুডিওর পক্ষে এটির জন্য দুর্দান্ত সমর্থন রয়েছে যাতে এটি এই বয়লারপ্লেটটি স্বয়ংক্রিয়ভাবে উত্পন্ন করতে পারে এবং এটি সঠিক হয় বা নাম না দেওয়া হলে আপনাকে দেখাতে পারে। আমাদের উদাহরণের ভিত্তিতে আমাদের পদ্ধতিটির নাম দেওয়া হয়েছে "জাভা_ডেমার_অ্যান্ড্রয়েডিয়োস্ক্পেক্সাম্পল_কোড়রেপ্পার_কন্টেনেটমাইস্ট্রিং উইথসিপিস্ট্রিং" কারণ এটি "এডেমার.অ্যান্ড্রয়েডিয়োস্কেপেক্সাম্পল" আমাদের প্যাকেজ, সুতরাং আমরা "প্রতিস্থাপন করব"। "_" দ্বারা, কোরআর্পার হ'ল ক্লাস যেখানে আমরা দেশীয় পদ্ধতির সাথে লিঙ্ক করছি এবং "কনক্যাটেনেটমাইস্ট্রিং উইথসিপিস্ট্রিং" হ'ল পদ্ধতিটির নাম।

যেহেতু আমাদের পদ্ধতিটি সঠিকভাবে ঘোষণা করা হয়েছে এটি এখন আর্গুমেন্টগুলি বিশ্লেষণ করার সময়, প্রথম প্যারামিটার JNIEnvএটির একটি পয়েন্টার যা জেএনআই স্টাফগুলিতে আমাদের অ্যাক্সেস রয়েছে, এটি আমাদের পক্ষে গুরুত্বপূর্ণ যেহেতু আপনি শীঘ্রই দেখতে পাবেন our দ্বিতীয়টি হ'ল jobjectএটি হ'ল আপনি এই পদ্ধতিটি কল করতে যে অবজেক্টটি ব্যবহার করেছিলেন of আপনি এটি জাভা হিসাবে " এটি " হিসাবে ভাবতে পারেন , আমাদের উদাহরণে আমাদের এটি ব্যবহারের দরকার নেই, তবে আমাদের এখনও এটি ঘোষণা করতে হবে। এই জবজেক্টের পরে, আমরা পদ্ধতির আর্গুমেন্টগুলি পেতে যাচ্ছি। যেহেতু আমাদের পদ্ধতির কেবল একটি যুক্তি রয়েছে - একটি স্ট্রিং "মাই স্ট্রিং", আমাদের একই নামের সাথে একটি "জাস্ট্রিং" রয়েছে। এছাড়াও লক্ষ্য করুন যে আমাদের রিটার্নের ধরণটিও একটি জাস্ট্রিং। জাভা / জেএনআই প্রকার সম্পর্কে আরও তথ্যের জন্য আমাদের জাভা পদ্ধতিটি একটি স্ট্রিং ফিরিয়ে দেয় কারণ এটি পড়ুন।

চূড়ান্ত পদক্ষেপটি হ'ল আমরা সিপিপি সাইডে ব্যবহার করি এমন ধরণের জেএনআই প্রকারকে রূপান্তর করা। উদাহরণস্বরূপ, আমরা রূপান্তর করা হয় jstringএকটি থেকে const char *পাঠানোর এটা সিপিপি রূপান্তরিত, ফলে পাওয়ার ফিরে রূপান্তর jstring। জেএনআই-তে অন্য সমস্ত পদক্ষেপ হিসাবে, এটি শক্ত নয়; এটি কেবলমাত্র বয়লারপ্লিটড, সমস্ত কাজ JNIEnv*যুক্তি দ্বারা আমরা সম্পন্ন করি যখন আমরা কল করি GetStringUTFCharsএবং করি NewStringUTF। এটির পরে আমাদের কোড অ্যান্ড্রয়েড ডিভাইসগুলিতে চালানোর জন্য প্রস্তুত, একবার দেখে নেওয়া যাক।

AndroidStudio অ্যান্ড্রয়েড


7
দুর্দান্ত ব্যাখ্যা
RED.Skull

9
আমি এটি পাই না - তবে এসও
মাইকেল রডরিগেস

16
@ ademar111190 এখন পর্যন্ত সর্বাধিক সহায়ক পোস্ট। এটি বন্ধ করা উচিত ছিল না।
জ্যারেড বুরোজ 15

6
@ জারেডবুরোস, আমি সম্মতি জানাই। পুনরায় খুলতে ভোট দিয়েছেন।
সর্বশক্তিমান

3
@ কেভিআইএসএইচ আপনাকে প্রথমে অবজেক্টিভ-সি-তে র‌্যাপারটি প্রয়োগ করতে হবে, তারপরে আপনি আপনার ব্রিজিং হেডার ফাইলে র‌্যাপার শিরোনামটি দ্রুতগতিতে অবজেক্টিভ-সি র‌্যাপারটি অ্যাক্সেস করতে পারবেন। এখন পর্যন্ত সুইফটে সরাসরি সি ++ অ্যাক্সেস করার কোনও উপায় নেই। আরও তথ্যের জন্য দেখুন stackoverflow.com/a/24042893/1853977
ক্রিস

3

উপরের উত্তরের উত্তরে বর্ণিত পদ্ধতিটি স্ক্যাপিক্স ল্যাঙ্গুয়েজ ব্রিজ দ্বারা সম্পূর্ণ স্বয়ংক্রিয়ভাবে করা যেতে পারে যা সরাসরি সি ++ হেডার থেকে ফ্লাইয়ে মোড়কের কোড উত্পন্ন করে। এখানে একটি উদাহরণ :

C ++ এ আপনার ক্লাসটি সংজ্ঞায়িত করুন:

#include <scapix/bridge/object.h>

class contact : public scapix::bridge::object<contact>
{
public:
    std::string name();
    void send_message(const std::string& msg, std::shared_ptr<contact> from);
    void add_tags(const std::vector<std::string>& tags);
    void add_friends(std::vector<std::shared_ptr<contact>> friends);
};

এবং এটিকে সুইফট থেকে কল করুন:

class ViewController: UIViewController {
    func send(friend: Contact) {
        let c = Contact()

        contact.sendMessage("Hello", friend)
        contact.addTags(["a","b","c"])
        contact.addFriends([friend])
    }
}

এবং জাভা থেকে:

class View {
    private contact = new Contact;

    public void send(Contact friend) {
        contact.sendMessage("Hello", friend);
        contact.addTags({"a","b","c"});
        contact.addFriends({friend});
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.