← Volver al listado de tecnologías

Integración con Redes Sociales y Game Center/Google Play Games

Por: Artiko
defoldsocialgame-centergoogle-play-gamesleaderboardslogros

Integración con Redes Sociales y Game Center/Google Play Games

La integración social es clave para el engagement y la viralidad de tu juego móvil. Esta guía te enseñará a implementar un sistema completo de funciones sociales.

Configuración Base de Servicios Sociales

1. Game Center (iOS) Setup

Configuración iOS

# game.project
[ios]
bundle_identifier = com.miestudio.mijuego
infoplist = /bundles/ios/Info.plist

[project]
dependencies = https://github.com/defold/extension-gamekit/archive/main.zip

Info.plist

<!-- Game Center Configuration -->
<key>UIRequiredDeviceCapabilities</key>
<array>
    <string>gamekit</string>
</array>

<!-- Background modes for Game Center -->
<key>UIBackgroundModes</key>
<array>
    <string>gamekit</string>
</array>

2. Google Play Games Setup

AndroidManifest.xml

<!-- Google Play Games Services -->
<meta-data android:name="com.google.android.gms.games.APP_ID"
    android:value="@string/app_id" />

<meta-data android:name="com.google.android.gms.version"
    android:value="@integer/google_play_services_version" />

<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Strings.xml

<resources>
    <string name="app_id">123456789012</string>
    <string name="leaderboard_high_scores">CgkI123456789EAIQAQ</string>
    <string name="achievement_first_win">CgkI123456789EAIQBA</string>
</resources>

3. Social Manager Core

Sistema Central de Gestión Social

-- social_manager.script
local M = {}

function init(self)
    self.platform = sys.get_sys_info().system_name
    self.authenticated = false
    self.player_info = {}
    self.achievements = {}
    self.leaderboards = {}

    -- Configuración
    self.config = {
        auto_authenticate = true,
        show_welcome_banner = true,
        cache_achievements = true,
        offline_mode = false
    }

    -- Estados
    self.authentication_in_progress = false
    self.pending_operations = {}

    print("Social Manager initialized for platform: " .. self.platform)
end

function M.initialize(self, callback)
    if self.platform == "iPhone OS" then
        self:initialize_game_center(callback)
    elseif self.platform == "Android" then
        self:initialize_google_play_games(callback)
    else
        print("Social features not available on this platform")
        if callback then callback(false, "unsupported_platform") end
    end
end

function M.authenticate(self, callback)
    if self.authentication_in_progress then
        table.insert(self.pending_operations, {type = "authenticate", callback = callback})
        return
    end

    self.authentication_in_progress = true

    if self.platform == "iPhone OS" then
        self:authenticate_game_center(callback)
    elseif self.platform == "Android" then
        self:authenticate_google_play_games(callback)
    end
end

function M.initialize_game_center(self, callback)
    if gamekit then
        gamekit.set_callback(function(self, message_id, message)
            M.handle_game_center_callback(self, message_id, message)
        end)

        -- Autenticar automáticamente si está configurado
        if self.config.auto_authenticate then
            self:authenticate_game_center(callback)
        end
    else
        print("GameKit extension not available")
        if callback then callback(false, "gamekit_not_available") end
    end
end

function M.authenticate_game_center(self, callback)
    if not gamekit then
        if callback then callback(false, "gamekit_not_available") end
        return
    end

    gamekit.authenticate(function(self, result)
        self.authentication_in_progress = false

        if result.success then
            self.authenticated = true
            self.player_info = {
                player_id = result.player_id,
                display_name = result.display_name,
                alias = result.alias
            }

            print("Game Center authentication successful")
            print("Player: " .. (result.display_name or result.alias))

            -- Cargar logros y leaderboards
            self:load_game_center_data()

            if callback then callback(true, result) end
        else
            print("Game Center authentication failed: " .. (result.error or "Unknown error"))
            if callback then callback(false, result.error) end
        end

        -- Procesar operaciones pendientes
        self:process_pending_operations()
    end)
end

function M.handle_game_center_callback(self, message_id, message)
    if message_id == gamekit.MSG_AUTHENTICATION then
        -- Manejar cambios en autenticación
        if message.authenticated then
            print("Game Center: Player authenticated")
        else
            print("Game Center: Player signed out")
            self.authenticated = false
            self.player_info = {}
        end

    elseif message_id == gamekit.MSG_ACHIEVEMENT then
        self:handle_achievement_response(message)

    elseif message_id == gamekit.MSG_LEADERBOARD then
        self:handle_leaderboard_response(message)
    end
end

return M

Achievements System

1. Achievement Manager

Sistema de Logros

-- achievement_manager.lua
local M = {}

function init(self)
    self.achievements = {}
    self.local_progress = {}
    self.social_manager = require "main.social_manager"

    -- Definir logros del juego
    self:setup_achievements()
end

function M.setup_achievements(self)
    self.achievements = {
        first_level = {
            id = "first_level",
            ios_id = "com.miestudio.mijuego.first_level",
            android_id = "CgkI123456789EAIQBA",
            name = "Primer Nivel",
            description = "Completa tu primer nivel",
            points = 10,
            hidden = false,
            incremental = false
        },

        score_1000 = {
            id = "score_1000",
            ios_id = "com.miestudio.mijuego.score_1000",
            android_id = "CgkI123456789EAIQBB",
            name = "Puntuación Alta",
            description = "Alcanza 1000 puntos",
            points = 20,
            hidden = false,
            incremental = false
        },

        level_master = {
            id = "level_master",
            ios_id = "com.miestudio.mijuego.level_master",
            android_id = "CgkI123456789EAIQBC",
            name = "Maestro de Niveles",
            description = "Completa 50 niveles",
            points = 50,
            hidden = false,
            incremental = true,
            steps = 50
        },

        coin_collector = {
            id = "coin_collector",
            ios_id = "com.miestudio.mijuego.coin_collector",
            android_id = "CgkI123456789EAIQBD",
            name = "Coleccionista",
            description = "Recolecta 10,000 monedas",
            points = 30,
            hidden = false,
            incremental = true,
            steps = 10000
        },

        secret_finder = {
            id = "secret_finder",
            ios_id = "com.miestudio.mijuego.secret_finder",
            android_id = "CgkI123456789EAIQBE",
            name = "Explorador Secreto",
            description = "Encuentra la sala secreta",
            points = 100,
            hidden = true,
            incremental = false
        }
    }
end

function M.unlock_achievement(self, achievement_id, progress)
    local achievement = self.achievements[achievement_id]
    if not achievement then
        print("Unknown achievement: " .. achievement_id)
        return false
    end

    progress = progress or (achievement.incremental and 1 or 100)

    -- Actualizar progreso local
    if not self.local_progress[achievement_id] then
        self.local_progress[achievement_id] = 0
    end

    if achievement.incremental then
        self.local_progress[achievement_id] = self.local_progress[achievement_id] + progress
        local total_progress = self.local_progress[achievement_id]

        -- Verificar si se completó
        if total_progress >= achievement.steps then
            self:report_achievement_complete(achievement)
        else
            self:report_achievement_progress(achievement, total_progress)
        end
    else
        self.local_progress[achievement_id] = 100
        self:report_achievement_complete(achievement)
    end

    -- Guardar progreso localmente
    self:save_achievement_progress()

    return true
end

function report_achievement_complete(self, achievement)
    print("Achievement unlocked: " .. achievement.name)

    -- Reportar a plataforma social
    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" then
            self:report_ios_achievement(achievement.ios_id, 100)
        elseif self.social_manager.platform == "Android" then
            self:report_android_achievement(achievement.android_id)
        end
    end

    -- Mostrar notificación local
    self:show_achievement_notification(achievement)

    -- Trackear para analytics
    msg.post("main:/analytics", "track_event", {
        event = "achievement_unlocked",
        properties = {
            achievement_id = achievement.id,
            achievement_name = achievement.name,
            points = achievement.points
        }
    })
end

function report_achievement_progress(self, achievement, progress)
    local percent = math.floor((progress / achievement.steps) * 100)

    print(string.format("Achievement progress: %s - %d/%d (%d%%)",
          achievement.name, progress, achievement.steps, percent))

    -- Reportar progreso a plataforma social
    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" then
            self:report_ios_achievement(achievement.ios_id, percent)
        elseif self.social_manager.platform == "Android" then
            self:report_android_achievement_progress(achievement.android_id, progress)
        end
    end
end

function report_ios_achievement(self, achievement_id, percent_complete)
    if gamekit then
        gamekit.report_achievement(achievement_id, percent_complete, function(self, result)
            if result.success then
                print("iOS achievement reported successfully")
            else
                print("Failed to report iOS achievement: " .. (result.error or "Unknown"))
            end
        end)
    end
end

function report_android_achievement(self, achievement_id)
    if gpgs then
        gpgs.achievement_unlock(achievement_id, function(self, result)
            if result.success then
                print("Android achievement unlocked successfully")
            else
                print("Failed to unlock Android achievement: " .. (result.error or "Unknown"))
            end
        end)
    end
end

function report_android_achievement_progress(self, achievement_id, steps)
    if gpgs then
        gpgs.achievement_increment(achievement_id, steps, function(self, result)
            if result.success then
                print("Android achievement progress updated")
            else
                print("Failed to update Android achievement progress: " .. (result.error or "Unknown"))
            end
        end)
    end
end

function show_achievement_notification(self, achievement)
    -- Mostrar UI de achievement
    msg.post("main:/ui", "show_achievement_unlocked", {
        name = achievement.name,
        description = achievement.description,
        points = achievement.points,
        icon = achievement.icon or "default_achievement_icon"
    })
end

function M.show_achievements_ui(self)
    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" and gamekit then
            gamekit.show_achievements()
        elseif self.social_manager.platform == "Android" and gpgs then
            gpgs.show_achievements()
        end
    else
        -- Mostrar UI local de achievements
        msg.post("main:/ui", "show_local_achievements", {
            achievements = self.achievements,
            progress = self.local_progress
        })
    end
end

-- Helper functions
function save_achievement_progress(self)
    local save_data = json.encode(self.local_progress)
    sys.save(sys.get_save_file("main", "achievements"), save_data)
end

function load_achievement_progress(self)
    local save_file = sys.get_save_file("main", "achievements")
    local save_data = sys.load(save_file)

    if save_data then
        local ok, progress = pcall(json.decode, save_data)
        if ok then
            self.local_progress = progress
        end
    end
end

return M

2. Achievement Triggers

Sistema de Triggers para Logros

-- achievement_triggers.lua
local M = {}

function init(self)
    self.achievement_manager = require "main.achievement_manager"
    self.game_stats = {
        levels_completed = 0,
        total_score = 0,
        coins_collected = 0,
        enemies_defeated = 0,
        power_ups_used = 0,
        playtime_seconds = 0
    }

    -- Cargar estadísticas guardadas
    self:load_game_stats()
end

function M.on_level_complete(self, level_number, score, time)
    self.game_stats.levels_completed = self.game_stats.levels_completed + 1
    self.game_stats.total_score = self.game_stats.total_score + score

    -- Trigger achievements
    if self.game_stats.levels_completed == 1 then
        self.achievement_manager:unlock_achievement("first_level")
    end

    if self.game_stats.levels_completed >= 50 then
        self.achievement_manager:unlock_achievement("level_master", 1)
    end

    if score >= 1000 then
        self.achievement_manager:unlock_achievement("score_1000")
    end

    -- Achievement por tiempo
    if time <= 60 then  -- Completar en menos de 1 minuto
        self.achievement_manager:unlock_achievement("speed_runner")
    end

    self:save_game_stats()
end

function M.on_coin_collected(self, amount)
    self.game_stats.coins_collected = self.game_stats.coins_collected + amount

    -- Achievement incremental de monedas
    self.achievement_manager:unlock_achievement("coin_collector", amount)

    self:save_game_stats()
end

function M.on_enemy_defeated(self, enemy_type)
    self.game_stats.enemies_defeated = self.game_stats.enemies_defeated + 1

    -- Achievements específicos por tipo de enemigo
    if enemy_type == "boss" then
        self.achievement_manager:unlock_achievement("boss_slayer")
    end

    -- Achievement por cantidad total
    if self.game_stats.enemies_defeated >= 1000 then
        self.achievement_manager:unlock_achievement("enemy_destroyer")
    end

    self:save_game_stats()
end

function M.on_secret_area_found(self, area_id)
    -- Achievement secreto
    self.achievement_manager:unlock_achievement("secret_finder")

    -- Achievement por encontrar todas las áreas secretas
    local secret_areas_found = self:get_secret_areas_found()
    if secret_areas_found >= 10 then
        self.achievement_manager:unlock_achievement("master_explorer")
    end
end

function M.on_perfect_level(self, level_number)
    -- Nivel completado sin morir y recogiendo todos los items
    self.achievement_manager:unlock_achievement("perfectionist")
end

function M.on_daily_login(self, consecutive_days)
    if consecutive_days >= 7 then
        self.achievement_manager:unlock_achievement("daily_player")
    end

    if consecutive_days >= 30 then
        self.achievement_manager:unlock_achievement("dedicated_player")
    end
end

function M.check_playtime_achievements(self, session_time)
    self.game_stats.playtime_seconds = self.game_stats.playtime_seconds + session_time

    local hours_played = self.game_stats.playtime_seconds / 3600

    if hours_played >= 10 then
        self.achievement_manager:unlock_achievement("veteran_player")
    end

    if hours_played >= 100 then
        self.achievement_manager:unlock_achievement("master_player")
    end

    self:save_game_stats()
end

-- Helper functions
function save_game_stats(self)
    local save_data = json.encode(self.game_stats)
    sys.save(sys.get_save_file("main", "game_stats"), save_data)
end

function load_game_stats(self)
    local save_file = sys.get_save_file("main", "game_stats")
    local save_data = sys.load(save_file)

    if save_data then
        local ok, stats = pcall(json.decode, save_data)
        if ok then
            self.game_stats = stats
        end
    end
end

function get_secret_areas_found(self)
    -- Implementar conteo de áreas secretas encontradas
    return 0
end

return M

Leaderboards System

1. Leaderboard Manager

Sistema de Leaderboards

-- leaderboard_manager.lua
local M = {}

function init(self)
    self.leaderboards = {}
    self.local_scores = {}
    self.social_manager = require "main.social_manager"

    -- Configurar leaderboards
    self:setup_leaderboards()
end

function M.setup_leaderboards(self)
    self.leaderboards = {
        high_scores = {
            id = "high_scores",
            ios_id = "com.miestudio.mijuego.high_scores",
            android_id = "CgkI123456789EAIQAQ",
            name = "Puntuación Más Alta",
            score_format = "numeric",
            order = "descending"
        },

        fastest_times = {
            id = "fastest_times",
            ios_id = "com.miestudio.mijuego.fastest_times",
            android_id = "CgkI123456789EAIQAR",
            name = "Tiempos Más Rápidos",
            score_format = "time",
            order = "ascending"
        },

        levels_completed = {
            id = "levels_completed",
            ios_id = "com.miestudio.mijuego.levels_completed",
            android_id = "CgkI123456789EAIQAS",
            name = "Niveles Completados",
            score_format = "numeric",
            order = "descending"
        },

        weekly_challenge = {
            id = "weekly_challenge",
            ios_id = "com.miestudio.mijuego.weekly_challenge",
            android_id = "CgkI123456789EAIQAT",
            name = "Desafío Semanal",
            score_format = "numeric",
            order = "descending",
            reset_period = "weekly"
        }
    }
end

function M.submit_score(self, leaderboard_id, score, callback)
    local leaderboard = self.leaderboards[leaderboard_id]
    if not leaderboard then
        print("Unknown leaderboard: " .. leaderboard_id)
        if callback then callback(false, "unknown_leaderboard") end
        return
    end

    -- Guardar score localmente
    self:save_local_score(leaderboard_id, score)

    -- Verificar si es un record personal
    local is_personal_best = self:is_personal_best(leaderboard_id, score)

    if is_personal_best then
        print("New personal best! " .. leaderboard.name .. ": " .. score)

        -- Mostrar celebración de record personal
        msg.post("main:/ui", "show_personal_best", {
            leaderboard_name = leaderboard.name,
            score = score,
            previous_best = self:get_previous_best(leaderboard_id)
        })
    end

    -- Enviar a plataforma social si está autenticado
    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" then
            self:submit_ios_score(leaderboard.ios_id, score, callback)
        elseif self.social_manager.platform == "Android" then
            self:submit_android_score(leaderboard.android_id, score, callback)
        end
    else
        -- Solo guardar localmente
        if callback then callback(true, {local_only = true}) end
    end

    -- Trackear para analytics
    msg.post("main:/analytics", "track_event", {
        event = "score_submitted",
        properties = {
            leaderboard_id = leaderboard_id,
            score = score,
            is_personal_best = is_personal_best
        }
    })
end

function submit_ios_score(self, leaderboard_id, score, callback)
    if gamekit then
        gamekit.report_score(leaderboard_id, score, function(self, result)
            if result.success then
                print("iOS score submitted successfully")
                if callback then callback(true, result) end
            else
                print("Failed to submit iOS score: " .. (result.error or "Unknown"))
                if callback then callback(false, result.error) end
            end
        end)
    end
end

function submit_android_score(self, leaderboard_id, score, callback)
    if gpgs then
        gpgs.leaderboard_submit_score(leaderboard_id, score, function(self, result)
            if result.success then
                print("Android score submitted successfully")
                if callback then callback(true, result) end
            else
                print("Failed to submit Android score: " .. (result.error or "Unknown"))
                if callback then callback(false, result.error) end
            end
        end)
    end
end

function M.show_leaderboard(self, leaderboard_id)
    local leaderboard = self.leaderboards[leaderboard_id]
    if not leaderboard then
        print("Unknown leaderboard: " .. leaderboard_id)
        return
    end

    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" and gamekit then
            gamekit.show_leaderboard(leaderboard.ios_id)
        elseif self.social_manager.platform == "Android" and gpgs then
            gpgs.show_leaderboard(leaderboard.android_id)
        end
    else
        -- Mostrar leaderboard local
        self:show_local_leaderboard(leaderboard_id)
    end
end

function M.show_all_leaderboards(self)
    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" and gamekit then
            gamekit.show_leaderboards()
        elseif self.social_manager.platform == "Android" and gpgs then
            gpgs.show_all_leaderboards()
        end
    else
        msg.post("main:/ui", "show_local_leaderboards", {
            leaderboards = self.leaderboards,
            scores = self.local_scores
        })
    end
end

function M.get_leaderboard_scores(self, leaderboard_id, callback)
    local leaderboard = self.leaderboards[leaderboard_id]
    if not leaderboard then
        if callback then callback(false, "unknown_leaderboard") end
        return
    end

    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" then
            self:get_ios_leaderboard_scores(leaderboard.ios_id, callback)
        elseif self.social_manager.platform == "Android" then
            self:get_android_leaderboard_scores(leaderboard.android_id, callback)
        end
    else
        -- Devolver scores locales
        local local_scores = self:get_local_leaderboard_scores(leaderboard_id)
        if callback then callback(true, {scores = local_scores, local_only = true}) end
    end
end

function get_ios_leaderboard_scores(self, leaderboard_id, callback)
    if gamekit then
        gamekit.load_leaderboard_scores(leaderboard_id, function(self, result)
            if callback then callback(result.success, result) end
        end)
    end
end

function get_android_leaderboard_scores(self, leaderboard_id, callback)
    if gpgs then
        gpgs.leaderboard_get_scores(leaderboard_id, function(self, result)
            if callback then callback(result.success, result) end
        end)
    end
end

-- Local score management
function save_local_score(self, leaderboard_id, score)
    if not self.local_scores[leaderboard_id] then
        self.local_scores[leaderboard_id] = {}
    end

    table.insert(self.local_scores[leaderboard_id], {
        score = score,
        timestamp = os.time(),
        player_name = "Jugador"
    })

    -- Mantener solo los mejores 10 scores
    local leaderboard = self.leaderboards[leaderboard_id]
    table.sort(self.local_scores[leaderboard_id], function(a, b)
        if leaderboard.order == "descending" then
            return a.score > b.score
        else
            return a.score < b.score
        end
    end)

    if #self.local_scores[leaderboard_id] > 10 then
        table.remove(self.local_scores[leaderboard_id])
    end

    self:save_local_scores()
end

function is_personal_best(self, leaderboard_id, score)
    local scores = self.local_scores[leaderboard_id]
    if not scores or #scores == 0 then
        return true
    end

    local leaderboard = self.leaderboards[leaderboard_id]
    local best_score = scores[1].score

    if leaderboard.order == "descending" then
        return score > best_score
    else
        return score < best_score
    end
end

function get_previous_best(self, leaderboard_id)
    local scores = self.local_scores[leaderboard_id]
    if scores and #scores > 0 then
        return scores[1].score
    end
    return 0
end

function save_local_scores(self)
    local save_data = json.encode(self.local_scores)
    sys.save(sys.get_save_file("main", "leaderboards"), save_data)
end

function load_local_scores(self)
    local save_file = sys.get_save_file("main", "leaderboards")
    local save_data = sys.load(save_file)

    if save_data then
        local ok, scores = pcall(json.decode, save_data)
        if ok then
            self.local_scores = scores
        end
    end
end

return M

Social Sharing

1. Share Manager

Sistema de Compartir en Redes Sociales

-- share_manager.lua
local M = {}

function init(self)
    self.share_providers = {
        native = true,
        facebook = false,
        twitter = false,
        instagram = false
    }

    -- Verificar disponibilidad de providers
    self:check_available_providers()
end

function M.check_available_providers(self)
    -- Verificar Facebook
    if facebook then
        self.share_providers.facebook = true
    end

    -- Native sharing siempre disponible en móviles
    if sys.get_sys_info().system_name == "iPhone OS" or
       sys.get_sys_info().system_name == "Android" then
        self.share_providers.native = true
    end
end

function M.share_score(self, score, level, image_path, callback)
    local share_text = string.format("¡Acabo de conseguir %d puntos en el nivel %d! ¿Puedes superarlo?", score, level)
    local share_url = "https://miapp.com/challenge/" .. score

    local share_data = {
        text = share_text,
        url = share_url,
        image = image_path,
        hashtags = {"gaming", "highscore", "mobile"}
    }

    self:show_share_options(share_data, callback)
end

function M.share_achievement(self, achievement_name, achievement_description, image_path, callback)
    local share_text = string.format("¡Desbloqueé el logro '%s'! %s", achievement_name, achievement_description)
    local share_url = "https://miapp.com/achievement/" .. achievement_name

    local share_data = {
        text = share_text,
        url = share_url,
        image = image_path,
        hashtags = {"achievement", "gaming", "mobile"}
    }

    self:show_share_options(share_data, callback)
end

function M.share_level_complete(self, level, time, score, image_path, callback)
    local share_text = string.format("¡Completé el nivel %d en %d segundos con %d puntos!", level, time, score)
    local share_url = "https://miapp.com/level/" .. level

    local share_data = {
        text = share_text,
        url = share_url,
        image = image_path,
        hashtags = {"levelcomplete", "gaming", "mobile"}
    }

    self:show_share_options(share_data, callback)
end

function show_share_options(self, share_data, callback)
    -- Mostrar opciones de compartir disponibles
    local options = {}

    if self.share_providers.native then
        table.insert(options, {
            id = "native",
            name = "Compartir",
            icon = "share_icon"
        })
    end

    if self.share_providers.facebook then
        table.insert(options, {
            id = "facebook",
            name = "Facebook",
            icon = "facebook_icon"
        })
    end

    if self.share_providers.twitter then
        table.insert(options, {
            id = "twitter",
            name = "Twitter",
            icon = "twitter_icon"
        })
    end

    if #options == 1 then
        -- Solo una opción disponible, usar directamente
        self:execute_share(options[1].id, share_data, callback)
    else
        -- Mostrar selector de opciones
        msg.post("main:/ui", "show_share_options", {
            options = options,
            share_data = share_data,
            callback = function(selected_provider)
                self:execute_share(selected_provider, share_data, callback)
            end
        })
    end
end

function execute_share(self, provider, share_data, callback)
    if provider == "native" then
        self:share_native(share_data, callback)
    elseif provider == "facebook" then
        self:share_facebook(share_data, callback)
    elseif provider == "twitter" then
        self:share_twitter(share_data, callback)
    end
end

function share_native(self, share_data, callback)
    -- Usar sistema nativo de compartir del SO
    local platform = sys.get_sys_info().system_name

    if platform == "iPhone OS" then
        -- iOS Activity View Controller
        self:share_ios_native(share_data, callback)
    elseif platform == "Android" then
        -- Android Intent
        self:share_android_native(share_data, callback)
    end
end

function share_ios_native(self, share_data, callback)
    -- Implementar usando extension nativa o webview
    local share_text = share_data.text
    if share_data.url then
        share_text = share_text .. " " .. share_data.url
    end

    -- En una implementación real, usarías una extensión nativa
    print("iOS Native Share: " .. share_text)

    if callback then callback(true, "shared_native") end
end

function share_android_native(self, share_data, callback)
    -- Implementar usando Android Intent
    local share_text = share_data.text
    if share_data.url then
        share_text = share_text .. " " .. share_data.url
    end

    -- En una implementación real, usarías una extensión nativa
    print("Android Native Share: " .. share_text)

    if callback then callback(true, "shared_native") end
end

function share_facebook(self, share_data, callback)
    if not facebook then
        if callback then callback(false, "facebook_not_available") end
        return
    end

    local fb_params = {
        link = share_data.url,
        quote = share_data.text
    }

    facebook.show_dialog("share", fb_params, function(result)
        local success = result and not result.error

        if success then
            print("Facebook share successful")

            -- Trackear share
            msg.post("main:/analytics", "track_event", {
                event = "content_shared",
                properties = {
                    platform = "facebook",
                    content_type = "score",
                    success = true
                }
            })
        else
            print("Facebook share failed: " .. (result.error or "Unknown"))
        end

        if callback then callback(success, result) end
    end)
end

function M.invite_friends(self, callback)
    local invite_data = {
        title = "¡Únete a la diversión!",
        message = "¡Descarga este increíble juego y vamos a competir!",
        url = "https://miapp.com/download",
        image = "/assets/invite_image.png"
    }

    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" and gamekit then
            -- Usar Game Center para invitar amigos
            self:invite_game_center_friends(invite_data, callback)
        elseif self.social_manager.platform == "Android" and gpgs then
            -- Usar Google Play Games para invitar
            self:invite_google_play_friends(invite_data, callback)
        end
    else
        -- Fallback a compartir normal
        self:share_native(invite_data, callback)
    end
end

function invite_game_center_friends(self, invite_data, callback)
    if gamekit then
        gamekit.show_request_dialog({
            message = invite_data.message,
            recipient_players = {},  -- Vacío para mostrar lista de amigos
        }, function(result)
            if callback then callback(result.success, result) end
        end)
    end
end

function invite_google_play_friends(self, invite_data, callback)
    if gpgs then
        gpgs.show_invite_dialog(invite_data.message, function(result)
            if callback then callback(result.success, result) end
        end)
    end
end

-- Screenshot sharing
function M.share_screenshot(self, callback)
    -- Tomar screenshot
    msg.post("@render:", "capture_screen", {}, function(self, message_id, message)
        if message_id == hash("screenshot_captured") then
            local image_path = message.path

            local share_data = {
                text = "¡Mira mi progreso en el juego!",
                url = "https://miapp.com/download",
                image = image_path,
                hashtags = {"gaming", "mobile", "screenshot"}
            }

            self:share_native(share_data, callback)
        end
    end)
end

return M

2. Friend System

Sistema de Amigos

-- friend_system.lua
local M = {}

function init(self)
    self.friends = {}
    self.friend_requests = {}
    self.social_manager = require "main.social_manager"
    self.leaderboard_manager = require "main.leaderboard_manager"
end

function M.load_friends(self, callback)
    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" then
            self:load_game_center_friends(callback)
        elseif self.social_manager.platform == "Android" then
            self:load_google_play_friends(callback)
        end
    else
        -- Cargar amigos locales
        self:load_local_friends(callback)
    end
end

function load_game_center_friends(self, callback)
    if gamekit then
        gamekit.load_friends(function(self, result)
            if result.success then
                self.friends = result.friends or {}
                print("Loaded " .. #self.friends .. " Game Center friends")
            else
                print("Failed to load Game Center friends: " .. (result.error or "Unknown"))
            end

            if callback then callback(result.success, result) end
        end)
    end
end

function load_google_play_friends(self, callback)
    if gpgs then
        gpgs.load_players(function(self, result)
            if result.success then
                self.friends = result.players or {}
                print("Loaded " .. #self.friends .. " Google Play friends")
            else
                print("Failed to load Google Play friends: " .. (result.error or "Unknown"))
            end

            if callback then callback(result.success, result) end
        end)
    end
end

function M.compare_scores_with_friends(self, leaderboard_id, callback)
    if #self.friends == 0 then
        self:load_friends(function(success, result)
            if success then
                self:get_friends_scores(leaderboard_id, callback)
            else
                if callback then callback(false, "no_friends_loaded") end
            end
        end)
    else
        self:get_friends_scores(leaderboard_id, callback)
    end
end

function get_friends_scores(self, leaderboard_id, callback)
    local leaderboard = self.leaderboard_manager.leaderboards[leaderboard_id]
    if not leaderboard then
        if callback then callback(false, "unknown_leaderboard") end
        return
    end

    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" then
            self:get_game_center_friends_scores(leaderboard.ios_id, callback)
        elseif self.social_manager.platform == "Android" then
            self:get_google_play_friends_scores(leaderboard.android_id, callback)
        end
    else
        -- Simular comparación local
        local mock_scores = self:generate_mock_friend_scores(leaderboard_id)
        if callback then callback(true, {scores = mock_scores, local_only = true}) end
    end
end

function get_game_center_friends_scores(self, leaderboard_id, callback)
    if gamekit then
        gamekit.load_leaderboard_scores(leaderboard_id, function(self, result)
            if result.success then
                -- Filtrar solo scores de amigos
                local friend_scores = self:filter_friend_scores(result.scores)
                if callback then callback(true, {scores = friend_scores}) end
            else
                if callback then callback(false, result.error) end
            end
        end)
    end
end

function filter_friend_scores(self, all_scores)
    local friend_scores = {}
    local friend_ids = {}

    -- Crear lookup table de IDs de amigos
    for _, friend in ipairs(self.friends) do
        friend_ids[friend.player_id] = true
    end

    -- Filtrar scores
    for _, score in ipairs(all_scores) do
        if friend_ids[score.player_id] then
            table.insert(friend_scores, score)
        end
    end

    return friend_scores
end

function M.challenge_friend(self, friend_id, challenge_type, challenge_data, callback)
    local challenge = {
        type = challenge_type,
        data = challenge_data,
        challenger_id = self.social_manager.player_info.player_id,
        challenger_name = self.social_manager.player_info.display_name,
        timestamp = os.time()
    }

    if self.social_manager.authenticated then
        if self.social_manager.platform == "iPhone OS" then
            self:send_game_center_challenge(friend_id, challenge, callback)
        elseif self.social_manager.platform == "Android" then
            self:send_google_play_challenge(friend_id, challenge, callback)
        end
    else
        print("Cannot send challenge - not authenticated")
        if callback then callback(false, "not_authenticated") end
    end
end

function send_game_center_challenge(self, friend_id, challenge, callback)
    if gamekit then
        local challenge_message = string.format(
            "¡%s te desafía! Tipo: %s",
            challenge.challenger_name,
            challenge.type
        )

        gamekit.send_challenge(friend_id, challenge_message, challenge.data, function(result)
            if callback then callback(result.success, result) end
        end)
    end
end

function M.show_friends_leaderboard(self, leaderboard_id)
    self:compare_scores_with_friends(leaderboard_id, function(success, result)
        if success then
            msg.post("main:/ui", "show_friends_leaderboard", {
                leaderboard_id = leaderboard_id,
                scores = result.scores,
                friends = self.friends
            })
        else
            print("Failed to load friends scores: " .. (result or "Unknown error"))
        end
    end)
end

-- Helper functions
function load_local_friends(self, callback)
    -- Cargar lista de amigos local (para testing)
    self.friends = {
        {player_id = "friend1", display_name = "Ana", alias = "Ana"},
        {player_id = "friend2", display_name = "Carlos", alias = "Carlos"},
        {player_id = "friend3", display_name = "María", alias = "María"}
    }

    if callback then callback(true, {friends = self.friends, local_only = true}) end
end

function generate_mock_friend_scores(self, leaderboard_id)
    local mock_scores = {}

    for _, friend in ipairs(self.friends) do
        table.insert(mock_scores, {
            player_id = friend.player_id,
            display_name = friend.display_name,
            score = math.random(100, 10000),
            rank = math.random(1, 100)
        })
    end

    return mock_scores
end

return M

Custom Social Features

1. Clan/Guild System

Sistema de Clanes

-- clan_system.lua
local M = {}

function init(self)
    self.current_clan = nil
    self.clan_members = {}
    self.clan_leaderboard = {}
    self.analytics = require "main.analytics_manager"
end

function M.create_clan(self, clan_name, clan_description, callback)
    local clan_data = {
        name = clan_name,
        description = clan_description,
        founder = self:get_player_id(),
        created_at = os.time(),
        member_count = 1,
        level = 1,
        experience = 0
    }

    -- En una implementación real, esto iría a tu backend
    self:send_to_backend("create_clan", clan_data, function(success, result)
        if success then
            self.current_clan = result.clan
            print("Clan created successfully: " .. clan_name)

            self.analytics:track_event("clan_created", {
                clan_name = clan_name,
                founder_id = self:get_player_id()
            })
        end

        if callback then callback(success, result) end
    end)
end

function M.join_clan(self, clan_id, callback)
    local join_data = {
        clan_id = clan_id,
        player_id = self:get_player_id(),
        player_name = self:get_player_name()
    }

    self:send_to_backend("join_clan", join_data, function(success, result)
        if success then
            self.current_clan = result.clan
            print("Joined clan: " .. result.clan.name)

            self.analytics:track_event("clan_joined", {
                clan_id = clan_id,
                clan_name = result.clan.name
            })
        end

        if callback then callback(success, result) end
    end)
end

function M.contribute_to_clan(self, contribution_type, amount, callback)
    if not self.current_clan then
        if callback then callback(false, "not_in_clan") end
        return
    end

    local contribution = {
        clan_id = self.current_clan.id,
        player_id = self:get_player_id(),
        type = contribution_type,  -- "coins", "experience", "trophies"
        amount = amount,
        timestamp = os.time()
    }

    self:send_to_backend("contribute_to_clan", contribution, function(success, result)
        if success then
            print(string.format("Contributed %d %s to clan", amount, contribution_type))

            self.analytics:track_event("clan_contribution", {
                clan_id = self.current_clan.id,
                contribution_type = contribution_type,
                amount = amount
            })

            -- Mostrar feedback
            msg.post("main:/ui", "show_clan_contribution", {
                type = contribution_type,
                amount = amount,
                total_contributed = result.total_contributed
            })
        end

        if callback then callback(success, result) end
    end)
end

function M.start_clan_challenge(self, challenge_type, duration_hours, callback)
    if not self.current_clan then
        if callback then callback(false, "not_in_clan") end
        return
    end

    local challenge = {
        clan_id = self.current_clan.id,
        type = challenge_type,
        duration_hours = duration_hours,
        start_time = os.time(),
        created_by = self:get_player_id()
    }

    self:send_to_backend("start_clan_challenge", challenge, function(success, result)
        if success then
            print("Clan challenge started: " .. challenge_type)

            self.analytics:track_event("clan_challenge_started", {
                clan_id = self.current_clan.id,
                challenge_type = challenge_type,
                duration_hours = duration_hours
            })
        end

        if callback then callback(success, result) end
    end)
end

-- Helper functions
function get_player_id(self)
    return self.social_manager.player_info.player_id or "local_player"
end

function get_player_name(self)
    return self.social_manager.player_info.display_name or "Jugador"
end

function send_to_backend(self, endpoint, data, callback)
    -- Implementar comunicación con backend
    -- Por ahora, simular respuestas
    timer.delay(1.0, false, function()
        if callback then callback(true, {success = true, data = data}) end
    end)
end

return M

Mejores Prácticas

1. User Experience

2. Technical

3. Engagement

4. Platform Guidelines

Esta implementación completa te proporciona un sistema social robusto que mejora significativamente el engagement y la retención de usuarios en tu juego móvil.